MSDN Community

Problem with DataGrid Row Styling in WPF
JD

Hi everyone,

I'm having a bit of trouble with styling the rows in my WPF DataGrid. I want to apply a different background color to rows based on a property in my data item. I've tried using a DataTrigger within a Style on the DataGridRow, but it doesn't seem to be working as expected.

Here's a snippet of my XAML:

<DataGrid.RowStyle>
    <Style TargetType="DataGridRow">
        <Style.Triggers>
            <DataTrigger Binding="{Binding Status}" Value="Active">
                <Setter Property="Background" Value="LightGreen" />
            </DataTrigger>
            <DataTrigger Binding="{Binding Status}" Value="Inactive">
                <Setter Property="Background" Value="LightCoral" />
            </DataTrigger>
        </Style.Triggers>
    </Style>
</DataGrid.RowStyle>

The Status property is a string. The DataGrid is bound to an ObservableCollection of objects that have a Status property.

Am I missing something obvious? Any help would be greatly appreciated!

AS

Hey John,

This is a common issue. The DataGrid often uses virtualization, and sometimes the row styles don't get applied correctly for all rows, especially when scrolling. A more robust way to achieve this is by using a DataGridTemplateColumn or by applying the style to the cells within the row.

However, your current approach with DataGridRow styling should generally work. Have you ensured that the Status property's value is exactly "Active" or "Inactive" (case-sensitive)? Also, make sure the DataContext for the row is correctly set up to expose the Status property.

Could you share a bit more about your data model and how the DataGrid is being populated?

JD

Thanks for the quick reply, Alice.

You're right about case sensitivity. I checked, and it's all correct. The `Status` property is indeed a string, and the values are exact matches.

Here's a simplified version of my data model:

public class ItemStatusInfo
{
    public string Name { get; set; }
    public string Status { get; set; } // "Active", "Inactive", "Pending"
    public DateTime Timestamp { get; set; }
}

And the `DataGrid` binding:

<DataGrid ItemsSource="{Binding ItemData}" ... >
    <DataGrid.Columns>
        <DataGridTextColumn Header="Name" Binding="{Binding Name}" />
        <DataGridTextColumn Header="Status" Binding="{Binding Status}" />
        <DataGridTextColumn Header="Timestamp" Binding="{Binding Timestamp, StringFormat='yyyy-MM-dd HH:mm'}" />
    </DataGrid.Columns>
    <!-- RowStyle is here -->
</DataGrid>

I'm not explicitly setting the DataContext for the rows; I assume the `DataGrid` handles that by default. I've also noticed that sometimes scrolling causes the colors to "jump" or disappear for certain rows, which aligns with your virtualization point.

Perhaps I should try applying the style to the cells as you suggested?

AS

Yes, John, that makes sense. The virtualization is likely the culprit.

To style the cells, you can use a DataGridTemplateColumn and place a TextBlock inside, applying the style to that TextBlock. Alternatively, you can define a style for DataGridCell within the row style.

Let's try the DataGridTemplateColumn approach for the Status column. Modify your XAML like this:

<DataGrid.Columns>
    <DataGridTextColumn Header="Name" Binding="{Binding Name}" />
    <DataGridTemplateColumn Header="Status">
        <DataGridTemplateColumn.CellTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding Status}">
                    <TextBlock.Style>
                        <Style TargetType="TextBlock">
                            <Style.Triggers>
                                <DataTrigger Binding="{Binding Status}" Value="Active">
                                    <Setter Property="Background" Value="LightGreen" />
                                    <Setter Property="Foreground" Value="DarkGreen" />
                                </DataTrigger>
                                <DataTrigger Binding="{Binding Status}" Value="Inactive">
                                    <Setter Property="Background" Value="LightCoral" />
                                    <Setter Property="Foreground" Value="DarkRed" />
                                </DataTrigger>
                                <DataTrigger Binding="{Binding Status}" Value="Pending">
                                    <Setter Property="Background" Value="LightYellow" />
                                    <Setter Property="Foreground" Value="Goldenrod" />
                                </DataTrigger>
                            </Style.Triggers>
                        </Style>
                    </TextBlock.Style>
                </TextBlock>
            </DataTemplate>
        </DataGridTemplateColumn.CellTemplate>
    </DataGridTemplateColumn>
    <DataGridTextColumn Header="Timestamp" Binding="{Binding Timestamp, StringFormat='yyyy-MM-dd HH:mm'}" />
</DataGrid.Columns>

<!-- You can keep the row style if you want to style the entire row, but for cell-specific styling, this is more reliable -->
<DataGrid.RowStyle>
    <Style TargetType="DataGridRow">
        <!-- Optional: If you still need row-level styling that isn't tied to a specific cell -->
    </Style>
</DataGrid.RowStyle>

This approach ensures that the styling is applied directly to the visual elements that are displayed, making it more compatible with virtualization. I've also added a trigger for "Pending" status and some foreground colors for better contrast.

Reply to this thread