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 🙂


Author: Categories: DataGrid, Uncategorized 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

  12. Yan
    August 19th, 2010 at 10:53 | #12

    The following just works! Try it!

  13. Mike Price
    November 4th, 2010 at 06:34 | #13

    Heres another very easy solution:
    For the Datagrid set a LoadingRow event.
    Use that to attach an event to each row:
    (I’ve shown a MouseLeftButtonUP but it could be any mouse event.)

    private void dgMyGrid_LoadingRow(object sender, DataGridRowEventArgs e)
    {
    e.Row.MouseLeftButtonUp +=MyGrid_RowClick;
    }

    then create the MyGrid_RowClick event:

    private void MyGrid_RowClick(object sender,
    System.Windows.Input.MouseButtonEventArgs e)
    {
    if (sender is DataGridRow)
    {
    //do your stuff
    }
    }

  14. shodson
    January 13th, 2011 at 13:50 | #14

    Why no just use PreviewMouseDoubleClick?

    Let’s say you bound a bunch of Thing objects to your grid

    Then…

    void thingsGrid_RowDoubleClick(object sender, MouseButtonEventArgs e)
    {
    if (thingsGrid.SelectedItem != null)
    {
    Thing thing = (Thing)dealersGrid.SelectedItem;
    MessageBox.Show(thing.SomeProperty);
    }
    }

  15. January 13th, 2011 at 14:01 | #15

    @shodson

    This blog post starts with that very event. Unless the API changes (it’s quite an old post), your event will also fire if you click into the empty area of the grid (if it only contains a few rows).

    You might also look at the solution from Mike Loux (see comments above).

    Cheers,
    Philipp

  16. whoever
    February 9th, 2011 at 23:28 | #16

    To find a cell:
    private void UpdateItemRow(DownloadCtlrStatus dlStatus)
    {
    // get the row
    DataGridRow row = (DataGridRow)datagrid1.ItemContainerGenerator.ContainerFromItem(dlStatus);
    if (row == null) return;

    // get the Cells
    DataGridCellsPresenter cellPresenter = FindVisualChild(row);

    // cell0
    DataGridCell cell = (DataGridCell)cellPresenter.ItemContainerGenerator.ContainerFromIndex(0);
    Image img = FindVisualChild(cell);
    if (img != null)
    img.GetBindingExpression(Image.SourceProperty).UpdateTarget();

    // cell10
    cell = (DataGridCell)cellPresenter.ItemContainerGenerator.ContainerFromIndex(9);
    TextBlock text = (TextBlock)cell.Content;
    text.GetBindingExpression(TextBlock.TextProperty).UpdateTarget();
    }

    FindVisualChild is a static helper function you can find on MSDN.

  17. nitin
    March 28th, 2011 at 05:39 | #17

    @Mike Loux
    nice
    it works for me

  18. nitin
    March 28th, 2011 at 05:41 | #18

    @Mike Loux
    nice
    it works for me
    but how to use this to edit that record we double clicked
    & how to get values of that rows

  19. saeed
    March 30th, 2011 at 05:06 | #19

    hi
    wow
    this was excellent.
    thanks a lot.

  20. Behzad Akbari
    April 8th, 2011 at 13:26 | #20

    Thank you for the helpful article. I spent a while to find some useful material about DataGrid Mouse Double Click Event.

  21. ANAND NAGARAJAN
    April 21st, 2011 at 00:29 | #21

    Hi Folks, try this out:
    Note: This works out for datagrids with whose binding source is a binding
    list of objects ex: a binding list of employees with public properties

    //create an event handler and hook up a delegate to it
    private System.Windows.Input.MouseButtonEventHandler populateTextBox;
    populateTextBox += doSOmething;
    dataGrid1.MouseDoubleClick+= new System.Windows.Input.MouseButtonEventHandler( populateTextBox);

    //Now the Code :
    private void doSOmething(object sender,System.Windows.Input.MouseButtonEventArgs e)
    {
    Class1 selecteditem = selectedItem as Class1;
    if (selecteditem != null)
    {
    //your logic here
    label1.Text = selectedItem.Age + ” “;

    }
    }

  22. Shawn
    May 19th, 2011 at 08:34 | #22

    @Mike Loux

    Love the simplicity and elegance. Thanks so much!

  23. Aksel
    December 5th, 2011 at 02:20 | #23

    Hi,
    I have come across this situation and need help, so in my wpf window there are two grids and a user control that we can drag. So i want that when its on grid1 it does thing1 and when its on grid2 it does thing2. How to implement this?

  24. addhillon
    March 13th, 2012 at 01:49 | #24

    simplest way to achieve this

    private void dgResult_MouseDoubleClick(object sender, MouseButtonEventArgs e)
    {
    }

  25. Alex
    August 20th, 2012 at 10:28 | #25

    @Mike Loux
    perfect ! Thanks Loux work fine for me 😉

  26. Tweek
    August 21st, 2012 at 15:31 | #26

    Worked Great wasted hours to get a solution working before seing yours . Thank you so much !

  1. No trackbacks yet.