Workaround for FrameworkElement.Triggers using Style and resolving issue

Many times it would be so handy to have Triggers available at the root FrameworkElement object type. Yes, the property exists, but it only supports EventTrigger at that level, while many times you’d want a different type of trigger, such as a DataTrigger, instead. Indeed, wouldn’t it be nice to be able to write this small XAML and ensure TextBlock will move a little more down in its parent Canvas when some toggle is set on the bound data item?

<!-- Note: This code doesn't work. -->
<TextBlock Text="..." Canvas.Top="10">
  <TextBlock.Triggers>
    <DataTrigger Binding="{Binding IsToggled}" Value="True">
      <Setter Property="Canvas.Top" Value="20"/>
    </DataTrigger>
  </TextBlock.Triggers>
</TextBlock>

Hey, you say, but there is a workaround: using an inline Style. More verbose, but the expected result would be the same, no?

<!-- Note: This code still doesn't work correctly, though. -->
<TextBlock Text="..." Canvas.Top="10">
  <TextBlock.Style>
    <Style TargetType="TextBlock">
      <Style.Triggers>
        <DataTrigger Binding="{Binding IsToggled}" Value="True">
          <Setter Property="Canvas.Top" Value="20"/>
        </DataTrigger>
      </Style.Triggers>
    </Style>
  </TextBlock.Style>
</TextBlock>

This should be working, but it doesn’t; you can check: at runtime the trigger will have no effect. And the root issue is difficult to spot if you are not aware of the priorities used by dependency properties upon obtaining their current values. Due to those priorities, the inline property setter that is applied directly to the TextBlock will override the value set by the DataTrigger inside the Style!

To resolve the issue you just need to move the property value setter inside the Style too:

<TextBlock Text="...">
  <TextBlock.Style>
    <Style TargetType="TextBlock">
      <Setter Property="Canvas.Top" Value="10"/>
      <Style.Triggers>
        <DataTrigger Binding="{Binding IsToggled}" Value="True">
          <Setter Property="Canvas.Top" Value="20"/>
        </DataTrigger>
      </Style.Triggers>
    </Style>
  </TextBlock.Style>
</TextBlock>

 

Advertisements

About Sorin Dolha

My passion is software development, but I also like physics.
This entry was posted in WPF and tagged , , , , . Bookmark the permalink.

4 Responses to Workaround for FrameworkElement.Triggers using Style and resolving issue

  1. gregsdennis says:

    The training for this is simple: when you set a property on the XAML element, it overrides any behavior set by inheritance or in styles. By setting the property in the style, you’re no longer overriding it.

    Like

    • gregsdennis says:

      Reason*, not training…

      Like

    • gregsdennis says:

      It’s not a workaround. It’s designed behavior.

      Like

      • Sorin Dolha says:

        Of course! Still, I think it would have been better for the WPF core to allow any trigger placed directly on an element and override the inline values that way, without requiring style with setters and triggers, and without the need to obtain the knowledge regarding the design and intended behavior; while indeed, for WPF – because of its so expressive and powerful – it’s way better to learn the theory first.

        Liked by 1 person

Add 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