Why does the DependencyProperty I set using a DataTrigger does not get its value?

This is a common mistake when developing WPF applications. It has happened to me countless times and I have seen people asking questions about it many times.

 

The Problem

I have a Style which defines a DataTrigger to change some property on a control based on a bounded value from the ViewModel. Let’s take a look at this example view XAML (I have removed irrelevant source code):

(...)
<Style x:Key="{x:Type Border}" TargetType="{x:Type Border}">
    <Style.Triggers>
        <DataTrigger Binding="{Binding BuildStatus}" Value="Ok">
            <Setter Property="Background" Value="Green"/>
        </DataTrigger>
        <DataTrigger Binding="{Binding BuildStatus}" Value="Broken">
            <Setter Property="Background" Value="Red"/>
        </DataTrigger>
    </Style.Triggers>
</Style>
(...)
<Border HorizontalAlignment="Center" VerticalAlignment="Center"
        Width="64" Height="64" Background="Transparent"
        BorderBrush="Black" BorderThickness="1,1,1,1" />
(...)

So we have a DataTrigger that changes the Background color of a Border accordingly to a BuildStatus property on our ViewModel. We do not want any color up until the ViewModel actually gets the build status, so we set the Border’s Background to Transparent. We then add a Button that can be used to toggle between two possible build status (ok and broken).

After we tie our View and its corresponding ViewModel displaying it on a window this is how our application looks when it is launched:

clip_image002

If you click on the change color Button you will see that, although we have specified our DataTriggers to change the color upon changes made to the build status nothing will happen to the build status indicator. Why is this happening?

 

The solution

The problem is that by setting the transparent color directly on the Border tag corresponding to the initial state color you override any value that may be set from the Style. So, in order for DataTrigger changed properties actually get set on your control you have to specify the default values on the Style through a property setter and not on the actual control instantiation:

(...)
<Style x:Key="{x:Type Border}" TargetType="{x:Type Border}">
    <Setter Property="Background" Value="Transparent"/>
    <Style.Triggers>
        <DataTrigger Binding="{Binding BuildStatus}" Value="Ok">
            <Setter Property="Background" Value="Green"/>
        </DataTrigger>
        <DataTrigger Binding="{Binding BuildStatus}" Value="Broken">
            <Setter Property="Background" Value="Red"/>
        </DataTrigger>
    </Style.Triggers>
</Style>
(...)
<Border HorizontalAlignment="Center" VerticalAlignment="Center"
        Width="64" Height="64"
        BorderBrush="Black" BorderThickness="1,1,1,1" />
(...)

I have bolded the changes that had to be done in order to fix this issue.

You can download a working copy of this sample by following this link.

Shout it kick it on DotNetKicks.com