4
votes

I have a DataGrid bound to a DataTable in a WPF application. The SelectionUnit of the DataGrid has to be set to Cell, but I'd also like to add a subtle highlight to the whole row so that on wide DataGrids, when the user scrolls off the selected cell they can still see the row highlighted.

This is a little problematic since the IsSelected property of the DataGridRow never gets set to true, because the Row isn't selected, the Cell is.

I don't mind is it's a little arrow in a sticky RowSelector or a highlight applied to the whole Row. Just need some way of highlighting which row is selected.

3
Thanks @MikeEason - the solution there is to change the SelectionUnit, but I need to retain single cell selection. – RBT

3 Answers

3
votes

I've played a bit here, nothing spectacular but is a working version:

    <Style TargetType="DataGridCell">
       <EventSetter Event="Selected" Handler="EventSetter_OnHandlerSelected"/>
       <EventSetter Event="LostFocus" Handler="EventSetter_OnHandlerLostFocus"/>
    </Style>

This is the codebehind:

    private void EventSetter_OnHandlerSelected(object sender, RoutedEventArgs e)
    {
        DataGridRow dgr = FindParent<DataGridRow>(sender as DataGridCell);
        dgr.Background = new SolidColorBrush(Colors.Red);
    }

    private void EventSetter_OnHandlerLostFocus(object sender, RoutedEventArgs e)
    {
        DataGridRow dgr = FindParent<DataGridRow>(sender as DataGridCell);
        dgr.Background = new SolidColorBrush(Colors.White);
    }

And this is the helper method to get the parent:

    public static T FindParent<T>(DependencyObject child) where T : DependencyObject
    {
        //get parent item
        DependencyObject parentObject = VisualTreeHelper.GetParent(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
            return FindParent<T>(parentObject);
    }

It's not MVVM, but taking into consideration that we're just working with the View elements .. i think this time it's not a must. So basically, on first selection you color the row, and on lost focus turn back to white the previous one and change color for the new selection.

1
votes

This works and is as MVVM as it gets. For better readability I used ExpressionConverter which is an amaizing way to make XAML more readable but more error prone. I also made a couple of changes to it to support mutlibindings but that's offtopic, you get the basic idea from the code: get the data context from the row and the CurrentCell property of the grid and compare if they are the same.

<DataGrid.Resources>
    <Style TargetType="{x:Type DataGridRow}">
        <Style.Triggers>
            <DataTrigger Value="True">
                <DataTrigger.Binding>
                    <MultiBinding Converter="{amazing:ExpressionConverter 'x[0] == x[1]'}">
                        <Binding RelativeSource="{RelativeSource Self}" Path="DataContext"></Binding>
                        <Binding ElementName="Grid" Path="CurrentCell" Converter="{amazing:ExpressionConverter 'x.Item'}"></Binding>
                    </MultiBinding>
                </DataTrigger.Binding>
                <Setter Property="Background" Value="Red"></Setter>
            </DataTrigger>
        </Style.Triggers>
    </Style>
</DataGrid.Resources>
0
votes

I found a great solution for this on MSDN. Linking to my answer on a similar question:

Highlight row when SelectionUnit is set to Cell