It seems to me that there is a major difference between the Blend-style Trigger
s found in the Interactivity namespace, and the classic Trigger
s available via Styles, ControlTemplate
s, 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.
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.
There are five types of triggers supported by WPF; they are: Property Trigger. Data Trigger. MultiTrigger.
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.
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.
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.
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>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With