Tuesday, December 8, 2015

WPF DataGrid MouseDoubleClick

After migrating all of my desktop app development from WinForms to WPF many years ago, I was often frustrated by moving from the DataGridView control to the DataGrid control. The old grid followed a classical model where you could easily enumerate rows and cells, and the events had quite predictable timing and behaviour. The DataGrid grid follows a binding model which enforces a different style of coding to customise behaviour and you need to understand how to use binding value converters effectively.

Double-clicking a cell in the WPF DataGrid seems to require some peculiar processing to determine which parent row was clicked so you can process the data item bound to the row. There are many conflicting samples to be found in web searches and some assume certain settings for the grid's cell selection mode. I believe the following handler code will work safely in all modes.

private void gridTasks_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
  var cell = FindParentControlType<DataGridCell>((DependencyObject)e.OriginalSource);
  if (cell != null)
  {
    var item = cell.DataContext as BoundClassType;
    if (item != null)
    {
      // You now have the data bound item instance
      // for the row containing the clicked cell
    }
  }
}

The FindParentControlType method is a real nuisance, and many versions of it can be found in samples online. Mine looks like this:

public static T FindParentControlType<T>(object source) where T : DependencyObject
{
  var dep = (DependencyObject)source;
  while ((dep != null) && (!(dep is T)))
  {
    dep = VisualTreeHelper.GetParent(dep);
  }
  return dep == null ? default(T) : (T)dep;
}