Mixing property triggers and data trigger in WPF

Property triggers and also data triggers are an excellent and powerful way to control your application’s behavior in WPF. These are covered in detail in various places on the net (e.g. https://www.wpf-tutorial.com/styles/trigger-datatrigger-event-trigger/). Most of the time, using either a trigger that was related to bound objects or a pure property trigger is enough.

Recently, I had the need to mix both trigger typed on a single control and struggeled to find a solution. The goal was to change the image of a control based on whether the mouse was hovering the control. This would call for a regular property trigger such as:

<ControlTemplate TargetType="Button">
    <Border Name="border" BorderThickness="0" 
                Background="Transparent">
          <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
    </Border>
    <ControlTemplate.Triggers>
        <Trigger Property="IsMouseOver" Value="True">
            <Setter Property="Background">
               <Setter.Value>
                   <ImageBrush ImageSource="/MyProjectName;component/Images/MyImage.jpg" />
               </Setter.Value>
            </Setter>
        </Trigger>
    </ControlTemplate.Triggers>
</ControlTemplate>

However, the image should be different on MouseOver based on some of the bound objects properties, like if the objects „IsInStock“ property is „true“, display a order icon, if it is „false“, display a „unavailable“ icon.

Normally, evaluating several trigger conditions calls for a multitrigger. Sadly, MultiTiggers can only evaluate control properties (e.g. IsMouseOver or IsSelected) and MultiDataTriggers can only be used for properties of the bound objects. Or so I thought.

With some fiddling I was able to find a way to use (or abuse?) the MultiDataTrigger to be able to also evaluate control properties, such as „IsMouseOver“:

<MultiDataTrigger>
 <MultiDataTrigger.Conditions>
  <Condition Binding="{Binding MyObject.IsInStock, TargetNullValue=false}" Value="False"/>
  <Condition Binding="{Binding RelativeSource={RelativeSource Mode=Self}, Path=IsMouseOver}" Value="True"/>
 </MultiDataTrigger.Conditions>
 <MultiDataTrigger.Setters>
  <Setter TargetName="image" Property="Source" Value="/MyProjectName;component/Images/MyImage.jpg"/>
    </MultiDataTrigger.Setters>
</MultiDataTrigger>

For it to work you would have to name a control „image“, obviously, e.g.:

<Image x:Name="image" Source="path/image/yours.png"/>

Simple, once you know about it.

Happy coding!

/chris

Share: