DataGrid context menu opened, over which row?

Dec 2, 2008 at 2:50 PM
When a DataGrid's context menu is opened and the user selects one of the menu items, and that menu item's Click event fires, how do I find out which row in the DataGrid the mouse cursor was over when the context menu was opened?

Handling the ContextMenuOpening and ContextMenuClosing events and manually figuring out from the pointer X and Y coordinates which row the pointer is over feels like a lot of work for something that should be a trivial task.
Dec 2, 2008 at 5:05 PM
Edited Dec 2, 2008 at 8:22 PM
Hi,

I have not tried specifically in the case of context menu opening ... but have a feeling it will be very similar to when you handle the mouse events. In other words, it is not obvious or straightforward!

I have just blogged on the subject and provided a solution that might work for you:

http://wpfadventures.wordpress.com/2008/12/02/wpf-datagrid-detecting-clicked-cell-and-row/

Let me know if this helps.

Regards,
Colin E.
--
http://wpfadventures.wordpress.com/ - my WPF blog
http://www.codeproject.com/KB/WPF/WPFDataGridExamples.aspx - WPF DataGrid Practical Examples



Coordinator
Dec 2, 2008 at 7:01 PM
How about setting the Context menu of DataGridRow using DataGrid.RowStyle property instead of DataGrid itself..... Following should explain in more detail

        <ContextMenu x:Key="mycm1">
            <ContextMenu.Items>
                <MenuItem Header="Item1" Click="MenuItem_Click"></MenuItem>
                <MenuItem Header="Item2"></MenuItem>
            </ContextMenu.Items>
        </ContextMenu>

        <Style x:Key="defaultRowStyle" TargetType="{x:Type dg:DataGridRow}">
            <Setter Property="ContextMenu" Value="{StaticResource mycm1}">
            </Setter>
        </Style>

        <dg:DataGrid x:Name="TheDataGrid" RowStyle="{StaticResource defaultRowStyle}" ... />

        private void MenuItem_Click(object sender, RoutedEventArgs e)
        {
            MenuItem item = sender as MenuItem;
            DataGridRow row = TheDataGrid.ItemContainerGenerator.ContainerFromItem(item.DataContext) as DataGridRow;
            ....
        }

Dec 3, 2008 at 8:31 AM
Edited Dec 3, 2008 at 8:33 AM
Except that if I set the row context menu, I lose out on any context menu functionality where there isn't any DataGridRow, such as below the data set but still within the DataGrid control. By iterating through the visual tree, all that happens is that I don't find a DataGridCell, and that can be handled by for example disabling menu items not relevant to non-rows. Iterating through the tree can also easily be moved to a helper class so that all that each instance of this code needs to deal with is whatever is specific to the DataGrid in question. Not perfect, but close enough.

Plus, I don't see how knowing which *row* was right-clicked on tells me anything about which *cell* the pointer was over at the time, but I could be wrong. This has come up as a need as well (I know, I probably should have updated the original post - sorry).
Dec 3, 2008 at 8:46 AM
Hi,

What about the solution I gave ...

http://wpfadventures.wordpress.com/2008/12/02/wpf-datagrid-detecting-clicked-cell-and-row/

This will give you the cell, row, cell value or column header that was clicked. I know ... it is a little complex - but that's the way it currently is with the DataGrid.

Regards,
Colin E.
--
http://wpfadventures.wordpress.com/ - my WPF blog
http://www.codeproject.com/KB/WPF/WPFDataGridExamples.aspx - WPF DataGrid Practical Examples




Dec 3, 2008 at 8:59 AM
Yes, Colin, that is pretty much the solution I'm going with (except I implemented it slightly differently). Thank you!