Pitfall with using triggers in Style and ControlTemplate

Using triggers, including datatriggers, in Style and ControlTemplate can be sometimes tricky. Check out the following two code snippets.

<Grid Background=”Red”>
<Grid.Style>
<Style TargetType=”{x:Type Grid}”>
<Style.Triggers>
<Trigger Property=”IsMouseOver” Value=”True”>
<Setter Property=”Background” Value=”Green”/>
</Trigger>
</Style.Triggers>
</Style>
</Grid.Style>
</Grid>

<Button Content=”Test” Foreground=”Red”>
<Button.Template>
<ControlTemplate TargetType=”{x:Type Button}”>
<Grid>
<ContentPresenter/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property=”IsMouseOver” Value=”True”>
<Setter Property=”Foreground” Value=”Green”/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Button.Template>
</Button>

Neither of them will work as expected, although they look fine. The reason here is that the property on the FrameworkElement overwrites the setters in Style or ControlTemplate, Therefore, any change caused by setters will not actually bring any change.  The following is the order in which WPF assign a value to a property.

1. The default value (as set by the FrameworkPropertyMetadata object)
2. The inherited value (if the FrameworkPropertyMetadata.Inherits flag is set and a value has been applied to an element somewhere up the containment hierarchy)
3. The value from a theme style (as discussed in Chapter 15)
4. The value from a project style (as discussed in Chapter 12)
5. The local value (in other words, a value you’ve set directly on this object using code or XAML)

To fix the above samples, the solution is quite as easy as the following

<Grid>
<Grid.Style>
<Style TargetType=”{x:Type Grid}”>
<Setter Property=”Background” Value=”Red”/>
<Style.Triggers>
<Trigger Property=”IsMouseOver” Value=”True”>
<Setter Property=”Background” Value=”Green”/>
</Trigger>
</Style.Triggers>
</Style>
</Grid.Style>
</Grid>

As you can see, instead directly assign a value to the property, use setter in Style, whoese value can be overrwritten when the trigger executes its setter.

Another solution is to use setters on higher level, with TargetName property targetting the element. See following.

<Button>
<Button.Template>
<ControlTemplate TargetType=”{x:Type Button}”>
<Grid>
<TextBlock x:Name=”textblock” Text=”Test” Foreground=”Red”/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property=”IsMouseOver” Value=”True”>
<Setter Property=”Foreground” TargetName=”textblock” Value=”Green”/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Button.Template>
</Button>

Advertisements

~ by Martin on December 12, 2008.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
%d bloggers like this: