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.
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());
}
}
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>