Skip to content

Instantly share code, notes, and snippets.

@marbel82
Last active March 5, 2020 10:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save marbel82/38435f3cd8a8a3b9e373a1e62d901f2b to your computer and use it in GitHub Desktop.
Save marbel82/38435f3cd8a8a3b9e373a1e62d901f2b to your computer and use it in GitHub Desktop.
WPF DataGrid: Show CancelEdit button when row is in edit mode + Cancel row edition

Question 1: WPF DataGrid - How to show a button in a row when the row is editing (detect edit mode)?

Question 2: WPF DataGrid - How to cancel edit row after validation error?

  • revision 3 (current) - code for the question 2

Useful links - binding, validation, DataGrid:

https://docs.microsoft.com/en-us/dotnet/framework/wpf/data/data-binding-overview
https://msdn.microsoft.com/en-us/magazine/ff714593.aspx
https://www.codeproject.com/Articles/30905/WPF-DataGrid-Practical-Examples
https://www.codeproject.com/Articles/863291/Validation-in-WPF
https://blog.magnusmontin.net/2013/08/26/data-validation-in-wpf/
https://www.wpfsharp.com/2012/02/03/how-to-disable-a-button-on-textbox-validationerrors-in-wpf/

WPF Examples: https://github.com/microsoft/WPF-Samples/tree/master/Data%20Binding/BindValidation


<!-- MainWindow.xaml -->
<Window x:Class="WpfApp1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp1"
        mc:Ignorable="d"
        Title="MainWindow" Height="240" Width="320">
    <Window.Resources>
        <local:DateConverter x:Key="DateConverter"/>
        <BooleanToVisibilityConverter x:Key="BoolToVisibilityConverter"/>
    </Window.Resources>
    <DockPanel>
        <StackPanel DockPanel.Dock="Top" Orientation="Horizontal">
            <Button Content="➕ Add" Width="50" Margin="4" Click="AddButton_Click"/>
        </StackPanel>
        <DataGrid x:Name="datagrid" DockPanel.Dock="Bottom" ItemsSource="{Binding Items}" AutoGenerateColumns="False" 
                  CanUserAddRows="False" SelectionMode="Single" SelectionUnit="FullRow" Margin="3">
            <DataGrid.Columns>
                <DataGridTextColumn Header="Something" Width="*" Binding="{Binding Something}" />
                <DataGridTextColumn Header="Date" Width="100" Binding="{Binding Date, Converter={StaticResource DateConverter}}" />
                <DataGridTemplateColumn Header="Action" Width="Auto" IsReadOnly="True" CanUserResize="False">
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <UniformGrid Rows="1">
                                <Button Content="" ToolTip="Cancel changes" Click="CancelChangesButton_Click" HorizontalAlignment="Center"
                                       Visibility="{Binding IsEditing, RelativeSource={RelativeSource AncestorType={x:Type DataGridRow}}, Converter={StaticResource BoolToVisibilityConverter}}"/>
                            </UniformGrid>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>
            </DataGrid.Columns>
        </DataGrid>
    </DockPanel>
</Window>
// MainWindow.xaml.cs
using System;
using System.Collections.ObjectModel;
using System.Globalization;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Threading;

namespace WpfApp1
{
    public partial class MainWindow : Window
    {
        public class SomethingItem
        {
            public string Something { get; set; }
            public DateTime Date { get; set; }
        }

        public ObservableCollection<SomethingItem> Items { get; } = new ObservableCollection<SomethingItem>();

        public MainWindow()
        {
            InitializeComponent();

            DataContext = this;
        }

        private void AddButton_Click(object sender, RoutedEventArgs e)
        {
            SomethingItem si = new SomethingItem
            {
                Something = "<write\u00A0something>",
                Date = DateTime.Now.Date,
            };
            Items.Add(si);

            // Move the focus to the new item
            datagrid.SelectedValue = si;
            datagrid.CurrentCell = new DataGridCellInfo(si, datagrid.Columns[0]);
            Dispatcher.BeginInvoke((Action)(() => datagrid.BeginEdit()), DispatcherPriority.Background);
        }

        private void CancelChangesButton_Click(object sender, RoutedEventArgs e)
        {
            datagrid.CancelEdit();
        }
    }
    
    public class DateConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (value is DateTime d)
                return d.ToString("d");
            else
                return "";
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (DateTime.TryParse((string)value, out DateTime dt))
                return dt.Date;
            else
                return DependencyProperty.UnsetValue;
        }
    }
}
@marbel82
Copy link
Author

marbel82 commented Mar 5, 2020

When I edit a cell and press cancel edit, I can't enter edit mode immediately again. I need to click another cell and come back.

CurrentCell should be restored.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment