Search code examples
c#wpfdatagrid

DataGrid does not execute double click event on editable cells


Goal

The goal is to execute a command on a double click on selected row.

Problem

When I double click a cell, it goes into edit mode and does not execute the command.

enter image description here

If I double click the empty cell on the right of column Data - it executes the command.

Also, if I set IsReadOnly to true, it works.. it just doesn't work with editable cells.

Question

Why does the double click event not work with editable cells?

Code to reproduce the problem

XAML

<DataGrid ItemsSource="{Binding SampleModels}" SelectedItem="{Binding SelectedItem}" AutoGenerateColumns="True" >
    <DataGrid.InputBindings>
        <MouseBinding Gesture="LeftDoubleClick" Command="{Binding Command}" />
    </DataGrid.InputBindings>
</DataGrid>

Model

public class SampleModel
{
    public int Id { get; set; }
    public string Data { get; set; }
}

View Model

public class SampleViewModel : BaseViewModel
{
    public ObservableCollection<SampleModel> SampleModels { get; set; }

    private SampleModel _selectedItem;

    public SampleModel SelectedItem
    {
        get { return _selectedItem; }
        set
        {
            _selectedItem = value;
            OnPropertyChanged();
        }
    }

    private void LoadData()
    {
        if(SampleModels == null)
        {
            SampleModels = new ObservableCollection<SampleModel>();
        }
        SampleModels.Clear();

        SampleModels.Add(new SampleModel { Id = 1, Data = "Item 1" });
        SampleModels.Add(new SampleModel { Id = 2, Data = "Item 2" });
    }

    public ICommand Command { get; }
    private void TestMethod()
    {
        var a = SelectedItem;
    }


    public SampleViewModel()
    {
        LoadData();
        Command = new RelayCommand(param => TestMethod());
    }

}

Solution

  • Why does the double click event not work with editable cells?

    Because the DataGrid control handles the double-click by entering the edit mode of the cell. How else would you be able to edit the cell?

    You could handle the double-click in the cells using an attached behaviour:

    public static class DoubleClickBehavior
    {
        public static ICommand GetCommand(UIElement element) =>
            (ICommand)element.GetValue(CommandProperty);
    
        public static void SetCommand(UIElement element, ICommand value) =>
            element.SetValue(CommandProperty, value);
    
        public static readonly DependencyProperty CommandProperty =
            DependencyProperty.RegisterAttached(
            "Command",
            typeof(ICommand),
            typeof(DoubleClickBehavior),
            new UIPropertyMetadata(null, OnChanged));
    
        private static void OnChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            UIElement element = (UIElement)d;
            if (e.NewValue is ICommand command)
            {
                element.PreviewMouseLeftButtonDown += OnMouseLeftButtonDown;
            }
            else
            {
                element.PreviewMouseLeftButtonDown -= OnMouseLeftButtonDown;
            }
        }
    
        private static void OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            if (e.ClickCount == 2)
            {
                UIElement element = (UIElement)sender;
                ICommand command = GetCommand(element);
                if (command != null)
                    command.Execute(null);
            }
        }
    }
    

    Sample Usage:

    <DataGrid ItemsSource="{Binding SampleModels}" SelectedItem="{Binding SelectedItem}" AutoGenerateColumns="True" >
        <DataGrid.InputBindings>
            <MouseBinding Gesture="LeftDoubleClick" Command="{Binding Command}" />
        </DataGrid.InputBindings>
        <DataGrid.CellStyle>
            <Style TargetType="DataGridCell">
                <Setter Property="local:DoubleClickBehavior.Command"
                        Value="{Binding DataContext.Command,RelativeSource={RelativeSource AncestorType=DataGrid}}" />
            </Style>
        </DataGrid.CellStyle>
    </DataGrid>