Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Blend Trigger vs. WPF Trigger

It seems to me that there is a major difference between the Blend-style Triggers found in the Interactivity namespace, and the classic Triggers available via Styles, ControlTemplates, etc, in WPF (I supposed this probably applies to SilverLight as well).

In WPF, when you set a Trigger with a Setter, you get two behaviours: if the trigger condition is met, the Setter is applied. However, once a Trigger is no longer satisfied, the previous value is restored. This is tremendously useful when programming UI.

I've tried to code a DataTrigger similarly using the Blend way: I applied ChangePropertyAction to my control, and have it trigger off of Interactivity DataTrigger using a Binding to my ViewModel.

<Rectangle x:Name="SecondaryHighlightBackground" Fill="#FF505050">
            <i:Interaction.Triggers>
                <ei:DataTrigger Binding="{Binding IsHighlighted}" Value="Value">
                    <ei:ChangePropertyAction PropertyName="Opacity" Value="0.5"/>
                </ei:DataTrigger>
            </i:Interaction.Triggers>
...
</Rectangle>

So this worked as expected... except I was stunned to discover that when I flip the IsHighlighted value to false, that the original Opacity of 0% is not restored (I set that lower down). To double check this, I wrote this example to verify:

<Window x:Class="TestWpfApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        x:Name="Window"
        Title="MainWindow"
        Width="640"
        Height="480">

    <Grid x:Name="LayoutRoot">
        <Button Name="button1"
                Width="173"
                Height="57"
                Margin="10,10,0,0"
                HorizontalAlignment="Left"
                VerticalAlignment="Top">
            <Button.Style>
                <Style TargetType="Button">
                    <Setter Property="Content" Value="foo" />
                    <Style.Triggers>
                        <DataTrigger Binding="{Binding IsMouseOver, ElementName=button1}" Value="True">
                            <Setter Property="Content" Value="bar" />
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
            </Button.Style>
        </Button>
    </Grid>
</Window>

The expected behaviour is that if you if mouse over the button, the content changes to 'bar'. Moving the mouse away restores content to 'Foo', as specified by the Style. The style sets the Content to avoid the property precedence issue.

My question is: Is two-way triggering really just missing in the Blend extensions, or is there a way to enable this somehow?

Am I missing something? I thought that was the very point of triggers, that they have this two-way functionality. I would like to continue using the Blend interactivity actions because I find them useful and intuitive, but this kind of thing forces me back into coding XAML by hand.

like image 736
cunningdave Avatar asked Mar 06 '13 21:03

cunningdave


People also ask

What are WPF triggers?

The WPF styling and templating model enables you to specify triggers within your Style. Essentially, triggers are objects that enable you to apply changes when certain conditions (such as when a certain property value becomes true , or when an event occurs) are satisfied.

How many types of triggers are there in WPF?

There are five types of triggers supported by WPF; they are: Property Trigger. Data Trigger. MultiTrigger.

What is trigger and how many types of triggers in WPF?

Triggers are used to create visual effects on controls and framework elements. Triggers are parts of styles and are always defined inside a style. Basically, there are 3 types of triggers, they are: Property Trigger.

What is trigger in XAML?

Triggers allow you to express actions declaratively in XAML that change the appearance of controls based on events or property changes. In addition, state triggers, which are a specialized group of triggers, define when a VisualState should be applied.


2 Answers

As stated in other answers there seems to be no automatic reversal of the value set by an Interaction trigger, but you can explicitly unset the value set by the trigger using DependencyProperty.UnsetValue and hence have the dependency property current value revert to the previous value like this:

<i:Interaction.Triggers>
  <ei:DataTrigger Binding="{Binding IsHighlighted}" Value="True">
    <ei:ChangePropertyAction PropertyName="Opacity" Value="0.5"/>
  </ei:DataTrigger>
  <ei:DataTrigger Binding="{Binding IsHighlighted}" Value="False">
    <ei:ChangePropertyAction PropertyName="Opacity" 
                             Value="{x:Static DependencyProperty.UnsetValue}"/>
  </ei:DataTrigger>
</i:Interaction.Triggers>

Disclaimer: I have actually only tested this on .NET Core 3.1 using the new open source packaging of xaml behaviors. Kept the classic i/ei namespaces for consistency with the original question.

like image 89
Magnus Avatar answered Nov 17 '22 01:11

Magnus


If I understand correctly you just have to provide the consideration for the other value in your trigger as well since it won't do it by default as you've taken control of that condition. Something like;

<i:Interaction.Triggers>
   <ei:DataTrigger Binding="{Binding IsHighlighted}" Value="True">
         <ei:ChangePropertyAction PropertyName="Opacity" Value="0.5"/>
   </ei:DataTrigger>
   <ei:DataTrigger Binding="{Binding IsHighlighted}" Value="False">
         <ei:ChangePropertyAction PropertyName="Opacity" Value="0"/>
   </ei:DataTrigger>
</i:Interaction.Triggers>
like image 1
Chris W. Avatar answered Nov 17 '22 00:11

Chris W.