Silverlight DataGrid: Make Right-click Select a Row

A slightly irking characteristic of many data grid libraries is that there seems to be a disconnect between expected usability in a grid, and the default behaviour of those same grids. I’ve found this to be a problem in all .NET grids that I’ve used including Infragistics and Microsoft’s WPF/Silverlight implementations.

For example, one thing I expect to be able to do is right-click on a grid’s row, and have it pull up a context menu with a list of actions to perform on it. Now that context menus have been added to Silverlight 4, half the battle is won, but you still can’t get the “correct” right-click behavior out of the box.

Here’s how to coax the grid to behave a bit more properly with VisualTreeHelper.

<!-- XAML -->
<UserControl x:Class="MyControl" 
    xmlns:grid="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"
    xmlns:toolkit="http://schemas.microsoft.com/winfx/2006/xaml/presentation/toolkit">
    
    <grid:DataGrid MouseRightButtonDown="_grid_MouseRightButtonDown">
        <!-- Define a context menu for our grid here -->
        <toolkit:ContextMenuService.ContextMenu>
            <toolkit:ContextMenu>
                <toolkit:MenuItem Header="Action!" />
            </toolkit:ContextMenu>
        </toolkit:ContextMenuService.ContextMenu>
    </grid:DataGrid>
</UserControl>
// Code-behind
private void _grid_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
{
    IEnumerable<UIElement> elementsUnderMouse = 
        VisualTreeHelper
            .FindElementsInHostCoordinates(e.GetPosition(null), this);
    DataGridRow row = 
        elementsUnderMouse
            .Where(uie => uie is DataGridRow)
            .Cast<DataGridRow>()
            .FirstOrDefault();
    if (row != null)
        _grid.SelectedItem = row.DataContext;
}

The code above uses VisualTreeHelper to find any UIElements under the mouse when the user performs a right-click. A set of UIElements is returned including grid rows and cells as well as a good number of other elements. We filter this set for an instance of DataGridRow, get is bound data item, then tell the grid to select that object.

Posted on September 1, 2010 from Calgary

About

My name is Brandur. I'm a polyglot software engineer and part-time designer working at Heroku in San Francisco, California. I'm a Canadian expat. My name is Icelandic. Drop me a line at brandur@mutelight.org.

Aside from technology, I'm interested in energy and how it relates to our society, travel, longboarding, muay thai, symphonic metal, and the guitar.

If you liked this article, consider finding me on Twitter.