WpfHowTo: Change DataGrid RowHeader Properties and/or Template When a Cell is Selected
This project shows the solution to a poster's question regarding manipulating the RowHeaderStyle, or other aspects of the row header, when a cell is selected.
Changing the style means changing a property, or the template.
This is best done by a Trigger, up where it needs to be done.
To achieve this my first choice would be an AttachedProperty.
public class AttachedProperties
{
public static bool GetIsFocussed(DependencyObject obj)
{
return (bool)obj.GetValue(IsFocussedProperty);
}
public static void SetIsFocussed(DependencyObject obj, bool value)
{
obj.SetValue(IsFocussedProperty, value);
}
public static readonly DependencyProperty IsFocussedProperty =
DependencyProperty.RegisterAttached("IsFocussed", typeof(bool), typeof(AttachedProperties), new UIPropertyMetadata(false));
}
The AttachedProperty gives us something to work with, when we are building in our own logic to a UI. The only safe and available alternative is the Tag property, which is a lazy alternative and not 'clean code', as far as readability is concerned.
That's pretty much it for the code, now let's look at how the Styles and Triggers find and use it in the UI.
Below are three examples of triggers.
1) Changing the row header template
This uses a style (DataGridRowHeaderStyle1) which has a DataTrigger on the attached property, when set to true, it replaces the whole Template (which is a property that a style can therefore set)
2) Changing a property for the row header
Most of the time you only want to change some of the properties, like Background. myDataGrid2 uses DataGridRowHeaderStyle2 which also triggers on the attached property to trigger just a property shown by the existing Control Template.
3) Changing DataGrid.RowHeaderStyle as requested.
The original question was regarding the 'global' DataGrid.RowHeaderStyle, so I also show how you can change all the RowHeaders upon one cell selection.
<Window.Resources>
<ControlTemplate x:Key="DifferentHeaderTemplate" TargetType="{x:Type DataGridRowHeader}">
<Grid Background="Red" Width="10" />
</ControlTemplate>
<Style x:Key="DataGridRowHeaderStyle1" TargetType="{x:Type DataGridRowHeader}">
<Style.Triggers>
<DataTrigger Binding="{Binding (local:AttachedProperties.IsFocussed), Mode=OneWay, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type DataGridRow}}}" Value="true">
<Setter Property="Template" Value="{DynamicResource DifferentHeaderTemplate}" />
</DataTrigger>
</Style.Triggers>
</Style>
<Style x:Key="DataGridRowHeaderStyle2" TargetType="{x:Type DataGridRowHeader}">
<Style.Triggers>
<DataTrigger Binding="{Binding (local:AttachedProperties.IsFocussed), Mode=OneWay, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type DataGridRow}}}" Value="true">
<Setter Property="Background" Value="Red" />
</DataTrigger>
</Style.Triggers>
</Style>
<Style x:Key="DataGridRowHeaderStyle3" TargetType="{x:Type DataGridRowHeader}">
<Setter Property="Template" Value="{DynamicResource DifferentHeaderTemplate}" />
</Style>
</Window.Resources>
<StackPanel>
<!-- Changing DataGridRowHeader ControlTemplate for selected cell -->
<DataGrid Margin="10" x:Name="myDataGrid1" ItemsSource="{Binding AllItems}" RowHeaderStyle="{DynamicResource DataGridRowHeaderStyle1}" >
<DataGrid.CellStyle>
<Style TargetType="{x:Type DataGridCell}">
<Setter Property="IsSelected" Value="{Binding (local:AttachedProperties.IsFocussed), Mode=OneWayToSource, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type DataGridRow}}}"/>
</Style>
</DataGrid.CellStyle>
</DataGrid>
<!-- Changing DataGridRowHeader Properties for selected cell -->
<DataGrid Margin="10" x:Name="myDataGrid2" ItemsSource="{Binding AllItems}" RowHeaderStyle="{DynamicResource DataGridRowHeaderStyle2}" >
<DataGrid.CellStyle>
<Style TargetType="{x:Type DataGridCell}">
<Setter Property="IsSelected" Value="{Binding (local:AttachedProperties.IsFocussed), Mode=OneWayToSource, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type DataGridRow}}}"/>
</Style>
</DataGrid.CellStyle>
</DataGrid>
<!-- Changing DataGrid.RowHeaderStyle -->
<DataGrid Margin="10" x:Name="myDataGrid3" ItemsSource="{Binding AllItems}" >
<DataGrid.Style>
<Style TargetType="DataGrid">
<Style.Triggers>
<DataTrigger Binding="{Binding (local:AttachedProperties.IsFocussed), Mode=OneWay, RelativeSource={RelativeSource Self}}" Value="true">
<Setter Property="DataGrid.RowHeaderStyle" Value="{DynamicResource DataGridRowHeaderStyle3}" />
</DataTrigger>
</Style.Triggers>
</Style>
</DataGrid.Style>
<DataGrid.CellStyle>
<Style TargetType="{x:Type DataGridCell}">
<Setter Property="IsSelected" Value="{Binding (local:AttachedProperties.IsFocussed), Mode=OneWayToSource, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type DataGrid}}}"/>
</Style>
</DataGrid.CellStyle>
</DataGrid>
</StackPanel>
Notice that the 'Row' level triggers set and look for the AttachedProperty in the same place, using RelativeSource, with traverses back up the Visual Tree looking for a control of the same AncestorType.
RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type DataGridRow}}
**
**For the third DataGrid level example, the triggers find the binding RelativeSource as:
From the cell: RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type DataGrid}}
**
**From the DataGrid: RelativeSource={RelativeSource Self}
This available in a demo project here.
This small article is part of a series of WPF "How To" articles, in response to real user questions on the MSDN WPF Forum.