Introduction
Sometimes, a simple checkbox
is usual for a data grid. I wanted to have a clear showing of an active status as green and red. For this, I found some code but as I wanted to visualize also the disable/readonly state, things were going to be complicated.

Step 1 - Simple Red and Green
As first, I wanted just a simple green cycle for true and red cycle for false. So I defined the column like:
<DataGridTemplateColumn Header="Active" >
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ToggleButton Style="{StaticResource ToggleStyleLight}"
IsChecked="{Binding IsActive, UpdateSourceTrigger=PropertyChanged}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
...
And a style using simple Triggers:
<Window.Resources>
<Style x:Key="ToggleStyleLight" TargetType="ToggleButton">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Border x:Name="innerBorder">
<Ellipse Fill="#60606000" Stroke="#FF000000" Stretch="Fill"
x:Name="statusLight" Width="15" Height="15" Margin="2"
VerticalAlignment="Center" HorizontalAlignment="Center"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter TargetName="statusLight"
Property="Fill" Value="#FF00FF00" />
</Trigger>
<Trigger Property="IsChecked" Value="False">
<Setter TargetName="statusLight"
Property="Fill" Value="#FFFF0000" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
Learning
This works fine but there was two aspects I wanted to resolve:
- Updated values were not reliably updated in the view model. I found out
UpdateSourceTrigger=PropertyChanged
solved the problem. - As long as the column is always readable, but when I started to disable the column it was not that simple. I found out
MultiTrigger
was required.
Using MultiTrigger
Using MultiTrigger
enabled me to define four different views depending on the combination of active and readonly. MultiTrigger
should be used as soon as you start using more than one condition.
When I start to get this done, I simple add a new trigger checking for IsEnabled
but that does not work. Because WPF/XAML is evaluating all triggers and if more than one sets the same property, you may not know which trigger wins.
The updated code is as given below:
<DataGridTemplateColumn Header="Active" IsReadOnly="{Binding IsActivatable}" >
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ToggleButton Style="{StaticResource ToggleStyleLight}"
IsChecked="{Binding IsActive, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
IsEnabled="{Binding IsActivatable}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
...
Style using simple MultiTrigger
:
<Window.Resources>
<Style x:Key="ToggleStyleLight" TargetType="ToggleButton">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Border x:Name="innerBorder">
<Ellipse Fill="#60606000" Stroke="#FF000000" Stretch="Fill"
x:Name="statusLight" Width="15" Height="15" Margin="2"
VerticalAlignment="Center" HorizontalAlignment="Center"/>
</Border>
<ControlTemplate.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="ToggleButton.IsEnabled" Value="True" />
<Condition Property="ToggleButton.IsChecked" Value="True" />
</MultiTrigger.Conditions>
<MultiTrigger.Setters>
<Setter TargetName="statusLight"
Property="Fill" Value="#FF00FF00" />
<Setter TargetName="statusLight"
Property="Stroke" Value="#FF000000" />
</MultiTrigger.Setters>
</MultiTrigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="ToggleButton.IsEnabled" Value="False" />
<Condition Property="ToggleButton.IsChecked" Value="True" />
</MultiTrigger.Conditions>
<MultiTrigger.Setters>
<Setter TargetName="statusLight"
Property="Fill" Value="#60606000" />
<Setter TargetName="statusLight"
Property="Stroke" Value="#FF00FF66" />
</MultiTrigger.Setters>
</MultiTrigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="ToggleButton.IsEnabled" Value="True" />
<Condition Property="ToggleButton.IsChecked" Value="False" />
</MultiTrigger.Conditions>
<MultiTrigger.Setters>
<Setter TargetName="statusLight"
Property="Fill" Value="#FFFF0000" />
<Setter TargetName="statusLight"
Property="Stroke" Value="#FF000000" />
</MultiTrigger.Setters>
</MultiTrigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="ToggleButton.IsEnabled" Value="False" />
<Condition Property="ToggleButton.IsChecked" Value="False" />
</MultiTrigger.Conditions>
<MultiTrigger.Setters>
<Setter TargetName="statusLight"
Property="Fill" Value="#60606000" />
<Setter TargetName="statusLight"
Property="Stroke" Value="#FFFF0066" />
</MultiTrigger.Setters>
</MultiTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Points of Interest
MultiTrigger
seams to be difficult if you see them for the first time. But effectively, they are very easy. There are not many samples available, especially in combination with DataGrid
s, so I decided to put this one online. As you see, it is simple to combine different Properties to activate a trigger or not. Also, it is important to know that simple Triggers may override each other.
History
- 17th January, 2020: Initial version