简体   繁体   中英

WPF MultiDataTrigger on Tag property only firing once

I have a situation where I need to select which animation to play on an event trigger based on a selection property. There are two events which always fire in the order A then B.

The solution I've come up with is to use the EventTrigger for A to set the Tag property of the element to 1, on the EvenTrigger for BI set it back to 0. I then have multiple MultiDataTriggers in the element style which have conditions to match on the Tag property value and the selection property, these trigger the corresponding animation.

This all works fine the first-time round, A triggers the first animation, B the second. However, when event A fires again for a second time the MultiDataTrigger no longer seems to trigger. To add to the confusion the animation for B continues to work. So long as the events alternate between A and B the event B animation will play, but not the event A one.

<Window x:Class="WpfTriggerTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfTriggerTest"
        xmlns:sys="clr-namespace:System;assembly=mscorlib"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid x:Name="rootLayout">
        <local:TestElement x:Name="testElement">
            <local:TestElement.Resources>
                <Storyboard x:Key="TriggerA">
                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Tag" Duration="0:0:0">
                        <ObjectAnimationUsingKeyFrames.KeyFrames>
                            <DiscreteObjectKeyFrame KeyTime="0:0:0" >
                                <DiscreteObjectKeyFrame.Value>
                                    <sys:Int32>1</sys:Int32>
                                </DiscreteObjectKeyFrame.Value>
                            </DiscreteObjectKeyFrame>
                        </ObjectAnimationUsingKeyFrames.KeyFrames>
                    </ObjectAnimationUsingKeyFrames>
                </Storyboard>
                <Storyboard x:Key="TriggerB">
                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Tag" Duration="0:0:0">
                        <ObjectAnimationUsingKeyFrames.KeyFrames>
                            <DiscreteObjectKeyFrame KeyTime="0:0:0" >
                                <DiscreteObjectKeyFrame.Value>
                                    <sys:Int32>0</sys:Int32>
                                </DiscreteObjectKeyFrame.Value>
                            </DiscreteObjectKeyFrame>
                        </ObjectAnimationUsingKeyFrames.KeyFrames>
                    </ObjectAnimationUsingKeyFrames>
                </Storyboard>
                <Storyboard x:Key="AnimA">
                    <ObjectAnimationUsingKeyFrames Storyboard.Target="{x:Reference rootLayout}" Storyboard.TargetProperty="Background" Duration="0:0:0">
                        <ObjectAnimationUsingKeyFrames.KeyFrames>
                            <DiscreteObjectKeyFrame>
                                <DiscreteObjectKeyFrame.Value>
                                    <SolidColorBrush Color="Red" />
                                </DiscreteObjectKeyFrame.Value>
                            </DiscreteObjectKeyFrame>
                        </ObjectAnimationUsingKeyFrames.KeyFrames>
                    </ObjectAnimationUsingKeyFrames>
                </Storyboard>
                <Storyboard x:Key="AnimB">
                    <ObjectAnimationUsingKeyFrames Storyboard.Target="{x:Reference rootLayout}" Storyboard.TargetProperty="Background" Duration="0:0:0">
                        <ObjectAnimationUsingKeyFrames.KeyFrames>
                            <DiscreteObjectKeyFrame>
                                <DiscreteObjectKeyFrame.Value>
                                    <SolidColorBrush Color="Green" />
                                </DiscreteObjectKeyFrame.Value>
                            </DiscreteObjectKeyFrame>
                        </ObjectAnimationUsingKeyFrames.KeyFrames>
                    </ObjectAnimationUsingKeyFrames>
                </Storyboard>
            </local:TestElement.Resources>
            <local:TestElement.Triggers>
                <EventTrigger RoutedEvent="local:TestElement.TriggerA">
                    <BeginStoryboard Storyboard="{StaticResource TriggerA}" />
                </EventTrigger>
                <EventTrigger RoutedEvent="local:TestElement.TriggerB">
                    <BeginStoryboard Storyboard="{StaticResource TriggerB}" />
                </EventTrigger>
            </local:TestElement.Triggers>
            <local:TestElement.Style>
                <Style TargetType="{x:Type local:TestElement}">
                    <Style.Triggers>
                        <MultiDataTrigger>
                            <MultiDataTrigger.Conditions>
                                <Condition Binding="{Binding Path=Tag, RelativeSource={RelativeSource Self}}" Value="1" />
                            </MultiDataTrigger.Conditions>
                            <MultiDataTrigger.EnterActions>
                                <BeginStoryboard Storyboard="{StaticResource AnimA}" />
                            </MultiDataTrigger.EnterActions>
                        </MultiDataTrigger>
                        <MultiDataTrigger>
                            <MultiDataTrigger.Conditions>
                                <Condition Binding="{Binding Path=Tag, RelativeSource={RelativeSource Self}}" Value="0" />
                            </MultiDataTrigger.Conditions>
                            <MultiDataTrigger.EnterActions>
                                <BeginStoryboard Storyboard="{StaticResource AnimB}" />
                            </MultiDataTrigger.EnterActions>
                        </MultiDataTrigger>
                    </Style.Triggers>
                </Style>
            </local:TestElement.Style>
        </local:TestElement>
        <Button Content="TriggerA" HorizontalAlignment="Left" Margin="51,45,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click" />
        <Button Content="TriggerB" HorizontalAlignment="Left" Margin="143,45,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click_1"/>
    </Grid>
</Window>

The code posted has been simplified, I removed the second condition from the MultiDataTrigger as it does not effect the issue at hand.

I've monitored the Tag property value and it is correctly getting set to 1 and 0 when the events fire. Why would the trigger only fire once? Or, is there a better approach to solve this problem?

I think the reason is that your storyboards keep running. You should stop the storyboard before running the other one. Have a look at this answer: WPF Fade In / Out only runs once

On another matter I would say that using storyboards for setting a simple value is an overkill. Consider using an Attached Behaviour or TriggerAction. See here for details and examples: Setting a property with an EventTrigger

The reason is that Tag's value did not change again. It was '1' and then it was '1' again.

The Dependency Property does not run any call back if the value did not change. I suggest before setting '1' set '0' which will do nothing and then set '1' for the actual Trigger.

Hope this helps

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM