How can I style WPF DataGrid to change the color of selected row when DataGrid lost its focus?
12 Answers
After ages of searching, I found a surprisingly simple way to do this that's cleaner than the Got/LostFocus approach posted earlier:
<DataGrid.Resources>
<SolidColorBrush x:Key="{x:Static SystemColors.InactiveSelectionHighlightBrushKey}" Color="DarkGray"/>
</DataGrid.Resources>
This just sets the inactive background colour to DarkGray, leaving the active background colour to the default, but you can change that too using the SystemColors.HighlightBrushKey too of course.
The foreground resource key for inactive selections is SystemColors.InactiveSelectionHighlightTextBrushKey.
Complete solution that works for 4.0. Note that this on the CellStyle.
<DataGrid.CellStyle>
<!--Override Highlighting so that its easy to see what is selected even when the control is not focused-->
<Style TargetType="{x:Type DataGridCell}">
<Style.Triggers>
<Trigger Property="IsSelected" Value="true">
<Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}" />
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}" />
<Setter Property="BorderBrush" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}" />
</Trigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsSelected}" Value="True" />
<Condition Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=DataGrid}, Path=IsKeyboardFocusWithin}" Value="False" />
</MultiDataTrigger.Conditions>
<MultiDataTrigger.Setters>
<Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}" />
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}" />
<Setter Property="BorderBrush" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}" />
</MultiDataTrigger.Setters>
</MultiDataTrigger>
</Style.Triggers>
</Style>
</DataGrid.CellStyle>
None of these answers gave me quite what I was looking for. The top rated by Steve Streeting changed other sections of the datagrid that I didn't want to change, and other answers weren't providing the inactive color change, but were properly targeting the row only. So here's a mixture of their answers that changes the inactive color, only on the rows and not in other places on the grid.
<DataGrid.Resources>
<Style TargetType="DataGridRow">
<Style.Resources>
<SolidColorBrush x:Key="{x:Static SystemColors.InactiveSelectionHighlightBrushKey}" Color="DarkGray"/>
</Style.Resources>
</Style>
</DataGrid.Resources>
LATE ANSWER:
This works in .Net 4.0, and you don't have to hardcode the color:
<Style TargetType="DataGridRow">
<Style.Resources>
<SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}" Color="{x:Static SystemColors.HighlightColor}" />
<SolidColorBrush x:Key="{x:Static SystemColors.ControlTextBrushKey}" Color="{x:Static SystemColors.HighlightTextColor}"/>
</Style.Resources>
</Style>
For .Net Framework 4.0 (or if you don't want to use the InactiveSelection... brush keys): Create a DataGridRow style/control template, and add these triggers:
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="true">
<Setter Property="Background" Value="{DynamicResource SelectionBrush}" />
</Trigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsSelected}" Value="True" />
<Condition Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=DataGrid}, Path=IsKeyboardFocusWithin}" Value="False" />
</MultiDataTrigger.Conditions>
<MultiDataTrigger.Setters>
<Setter Property="Background" Value="{DynamicResource InactiveSelectionBrush}" />
</MultiDataTrigger.Setters>
</MultiDataTrigger>
</ControlTemplate.Triggers>
You should define section "DataGrid.CellStyle" inside your DataGrid like this:
<DataGrid>
<DataGrid.CellStyle>
<Style TargetType="DataGridCell">
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="LightBlue"/>
</Trigger>
</Style.Triggers>
</Style>
</DataGrid.CellStyle>
</DataGrid>
Find an answer by myself.
Add to DataGrid's resources the brush, which can change its 'Color' property from code behind, and reference HighlightBrushKey to it:
<DataGrid.Resources>
<SolidColorBrush x:Key="SelectionColorKey" Color="DarkGray"/>
<Style TargetType="DataGridRow">
<Style.Resources>
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="{Binding Source={StaticResource SelectionColorKey}, Path=Color}"/>
</Style.Resources>
</Style>
</DataGrid.Resources>
Then add DataGrids event handlers to manually change the color:
private void DataGrid1_LostFocus(object sender, RoutedEventArgs e)
{
((SolidColorBrush)DataGrid1.Resources["SelectionColorKey"]).Color = Colors.DarkGray;
}
private void DataGrid1_GotFocus(object sender, RoutedEventArgs e)
{
((SolidColorBrush)DataGrid1.Resources["SelectionColorKey"]).Color = SystemColors.HighlightColor;
}
private void DataGrid1_LostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
((SolidColorBrush)DataGrid1.Resources["SelectionColorKey"]).Color = Colors.DarkGray;
}
For .NET 4.0 or higher: It is also possible to set the colors programmatically:
if (TestDataGrid.RowStyle == null)
{
TestDataGrid.RowStyle = new Style(typeof(DataGridRow));
}
// Set colors for the selected rows if focus is inactive
TestDataGrid.RowStyle.Resources.Add(SystemColors.ControlBrushKey, new SolidColorBrush(Colors.SkyBlue));
TestDataGrid.RowStyle.Resources.Add(SystemColors.ControlTextBrushKey, new SolidColorBrush(Colors.Black));
// Set colors for the selected rows if focus is active
TestDataGrid.RowStyle.Resources.Add(SystemColors.HighlightBrushKey, new SolidColorBrush(Colors.Red));
TestDataGrid.RowStyle.Resources.Add(SystemColors.HighlightTextBrushKey, new SolidColorBrush(Colors.White));
For .NET 4.5 or higher there is the following alternative to set the colors programmatically:
if (TestDataGrid.Resources == null)
{
TestDataGrid.Resources = new ResourceDictionary();
}
// Set colors for the selected rows if focus is inactive
TestDataGrid.Resources.Add(SystemColors.InactiveSelectionHighlightBrushKey, new SolidColorBrush(Colors.SkyBlue));
TestDataGrid.Resources.Add(SystemColors.InactiveSelectionHighlightTextBrushKey, new SolidColorBrush(Colors.Black));
// Set colors for the selected rows if focus is active
TestDataGrid.Resources.Add(SystemColors.HighlightBrushKey, new SolidColorBrush(Colors.Red));
TestDataGrid.Resources.Add(SystemColors.HighlightTextBrushKey, new SolidColorBrush(Colors.White));
I had a similar problem. The scenario was a DataGrid with colors assigned for: RowBackground and AlternatingRowBackground. When the DataGrid Lose Focus, the selected row became Gray, returning to the correct color when the DataGrid regained Focus by clicking on any row. This effect was unpleasant. I started from the solution proposed here by Steve Streeting:
<Style TargetType="DataGrid">
<Style.Resources>
<SolidColorBrush x:Key="{x:Static SystemColors.InactiveSelectionHighlightBrushKey}"
Color="LightGray"/>
</Style.Resources>
</Style>
but by changing Color = "Transparent".
<SolidColorBrush x:Key="{x:Static SystemColors.InactiveSelectionHighlightBrushKey}"
Color="Transparent"/>
this solved the problem in a simple and satisfactory way.
valid for .net 4.5
, not for .net 4.0
.
Hope this solution is useful