Search code examples
wpfdatagridborderdatatrigger

WPF DataGrid DataGridRow Selection Border and Spacing


I'm using the WPF DataGrid to display data and when the user selects a row, I'd like the background of the entire row to be highlighted (with a gradient) and also to have a border. I've been using the following code, which works for the most part:

    <Style TargetType="DataGridRow">
        <Setter Property="BorderBrush" Value="Transparent" />
        <Setter Property="BorderThickness" Value="0" />
    <Style.Triggers>
        <DataTrigger Binding="{Binding IsChecked}" Value="True">
            <Setter Property="BorderThickness" Value="1"/>
            <Setter Property="BorderBrush" Value="{StaticResource BorderColor}" />
            <Setter Property="Background" Value="{StaticResource BackgroundColor}" />
        </DataTrigger>
    </Style.Triggers>
    </Style>

This issue I'm having is with the border. If the BorderThickness is initially set to 0, then the entire Row "shifts over" to make space for the border when the DataTrigger is triggered. If I set the BorderThickness to 1 initially, then the highlighted Row is displayed correctly, but there is an empty border around the Row when it's in it's default state, causing the Row gridlines not to touch the edge.

Any ideas on how I could work around this?


Solution

  • I've found that tweaking visuals is much easier with ListBox instead of DataGrid so maybe that could be one way to go.

    Try this as a starting point:

    <ListBox>
        <ListBox.ItemContainerStyle>
            <Style TargetType="{x:Type ListBoxItem}">
                <Style.Triggers>
                    <DataTrigger Binding="{Binding IsChecked}" Value="True">
                        <Setter Property="BorderBrush" Value="{StaticResource BorderColor}" />
                        <Setter Property="Background" Value="{StaticResource BackgroundColor}" />
                    </DataTrigger>
                </Style.Triggers>
                <Setter Property="Background" Value="Transparent" />
                <Setter Property="BorderBrush" Value="Transparent" />
            </Style>
        </ListBox.ItemContainerStyle>
        <ListBox.ItemTemplate>
            <DataTemplate DataType="{x:Type local:MyClass}">
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="30" />
                        <ColumnDefinition Width="*" />
                    </Grid.ColumnDefinitions>
                    <CheckBox IsChecked="{Binding IsChecked}" />
                    <TextBlock Text="{Binding MyTextProperty}" Grid.Column="1" />
                </Grid>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
    

    This should set the correct border and background without moving elements of a selected row or showing surrounding gaps for unselected ones. Just replace local:MyClass with your class and customize the Grid contents for your scenario.

    See this answer on how to deal with MouseOver/Selected styles, I tried copying the template property setter into my example above and adjusting the Panel.Background and Border.BorderBrush setters which seems to work well.