Home > DataGrid, Uncategorized > Detecting Double Click Events on the WPF DataGrid

Detecting Double Click Events on the WPF DataGrid

March 21st, 2009

Either I missed the obvious solution, or there is indeed no simple way to catch double click events on a given row of Microsoft’s WPF DataGrid.

This snippet here fires the event whenever the grid is clicked - it doesn’t matter whether the user double-clicks into an empty area (no rows) or a row:

<!-- fires even if the user does not click a given row -->
<dg:DataGrid
  dg:DataGridRow.MouseDoubleClick="OnDoubleClick" />

 

As a result, I reverted to a workaround by searching the Visual Tree of the event source for an instance of type DataGridRow. In order to find the ancestor item, I used a snippet I posted here a while ago. Here’s the full code:

 

XAML:

<!-- just register a listener on the grid -->
<dg:DataGrid
  MouseDoubleClick="OnDoubleClick" />

 

Code-Behind:

/// <summary>
/// Handles double-clicks on datagrid rows.
/// </summary>
private void OnDoubleClick(object sender, MouseButtonEventArgs e)
{
  //search the object hierarchy for a datagrid row
  DependencyObject source = (DependencyObject) e.OriginalSource;
  var row = UIHelpers.TryFindParent<DataGridRow>(source);

  //the user did not click on a row
  if (row == null) return;

  //[insert great code here...]

  e.Handled = true;
}

 

UIHelper class providing the TryFindParent method:

(Snippet updated: 2009.09.14)

/// <summary>
/// Finds a parent of a given item on the visual tree.
/// </summary>
/// <typeparam name="T">The type of the queried item.</typeparam>
/// <param name="child">A direct or indirect child of the
/// queried item.</param>
/// <returns>The first parent item that matches the submitted
/// type parameter. If not matching item can be found, a null
/// reference is being returned.</returns>
public static T TryFindParent<T>(this DependencyObject child)                               where T : DependencyObject
{
  //get parent item
  DependencyObject parentObject = GetParentObject(child);

  //we've reached the end of the tree
  if (parentObject == null) return null;

  //check if the parent matches the type we're looking for
  T parent = parentObject as T;
  if (parent != null)
  {
    return parent;
  }
  else
  {
    //use recursion to proceed with next level
    return TryFindParent<T>(parentObject);
  }
}

/// <summary>
/// This method is an alternative to WPF's
/// <see cref="VisualTreeHelper.GetParent"/> method, which also
/// supports content elements. Keep in mind that for content element,
/// this method falls back to the logical tree of the element!
/// </summary>
/// <param name="child">The item to be processed.</param>
/// <returns>The submitted item's parent, if available. Otherwise
/// null.</returns>
public static DependencyObject GetParentObject(this DependencyObject child)
{
  if (child == null) return null;

  //handle content elements separately
  ContentElement contentElement = child as ContentElement;
  if (contentElement != null)
  {
    DependencyObject parent = ContentOperations.GetParent(contentElement);
    if (parent != null) return parent;

    FrameworkContentElement fce = contentElement as FrameworkContentElement;
    return fce != null ? fce.Parent : null;
  }

  //also try searching for parent in framework elements (such as DockPanel, etc)
  FrameworkElement frameworkElement = child as FrameworkElement;
  if (frameworkElement != null)
  {
    DependencyObject parent = frameworkElement.Parent;
    if (parent != null) return parent;
  }

  //if it's not a ContentElement/FrameworkElement, rely on VisualTreeHelper
  return VisualTreeHelper.GetParent(child);
}

 

Enjoy :-)

Tags:
  1. Suchit
    April 23rd, 2009 at 12:38 | #1

    Thanks a lot man :-) It works out great…..

  2. AC
    May 26th, 2009 at 14:19 | #2

    Using the WPF datagrid for the first time and even with the Windows form datagrid the event would fire no matter where the doubleclick was done.

    I found that the following “if” was all I needed to be check to see if a row was selected.

    private void datagrid1_MouseDoubleClick(object sender, MouseButtonEventArgs e)
    {

    if (e.LeftButton == MouseButtonState.Pressed & datagrid1.SelectedItem != null)

  3. July 1st, 2009 at 09:48 | #3

    AC,
    Your solution also fires the event if you have a selected row and click on an empty area of the grid. Be careful with this one.

    Furthermore, you don’t get the row, but the bound item ;)

  4. August 13th, 2009 at 15:24 | #4

    works out great with ListView too :

    var row = TryFindParent(source);

    And for databinding adepts, you still can catch your ObjectViewModel :

    ObjectViewModel object = row.Content as ObjectViewModel;

    Thanks a lot,
    Cam

  5. Mic
    November 23rd, 2009 at 21:00 | #5

    I’ve found an alternative for this which probably wont scale very well but appears to work for my DataGrid. Returns the underlying data bound object of the row under the mouse click:

    private T TryGetDataBoundItem(MouseButtonEventArgs e)
    {
    try
    {
    if (e.OriginalSource is FrameworkElement)
    {
    if (((FrameworkElement)(e.OriginalSource)).DataContext is T)
    return (T)((FrameworkElement)(e.OriginalSource)).DataContext;
    }
    }
    catch
    {
    }
    return default(T);
    }

  6. Erl
    December 17th, 2009 at 18:16 | #6

    Excellent Posting! Thanks for doing this!

  7. Gurkan
    December 31st, 2009 at 17:45 | #7

    Nice code. Thank you.

  8. Mike Loux
    March 31st, 2010 at 14:49 | #8

    I found that this method works like a charm for me:

    private void dgMyGrid_MouseDoubleClick(object sender, MouseButtonEventArgs e) {
    // Check if the user double-clicked a grid row and not something else
    DataGridRow row = ItemsControl.ContainerFromElement((DataGrid)sender, e.OriginalSource as DependencyObject) as DataGridRow;

    // If so, go ahead and do my thing
    if (row != null) BlahBlahBlah();
    }

    Seems pretty simple and elegant. HTH!

  9. Stefano
    May 14th, 2010 at 14:02 | #9

    Good Mike Loux,
    your solution is the best.

  10. Oscar
    July 9th, 2010 at 18:50 | #10

    @Mike Loux, please post the xaml definition of your grid, thank you.

  11. Ravi K Kashyap
    August 4th, 2010 at 12:24 | #11

    How to get the cell value from the selected row

  1. No trackbacks yet.