【问题标题】:WPF MultiDataTrigger on Tag property only firing once标签属性上的 WPF MultiDataTrigger 仅触发一次
【发布时间】:2019-07-14 01:26:11
【问题描述】:

我有一种情况,我需要根据选择属性选择要在事件触发器上播放的动画。有两个事件总是按 A 然后 B 的顺序触发。

我想出的解决方案是使用 EventTrigger for A 将元素的 Tag 属性设置为 1,在 EventTrigger for BI 上将其设置回 0。然后我在元素样式中有多个 MultiDataTrigger Tag 属性值和 selection 属性有条件匹配,触发相应的动画。

这在第一轮中一切正常,A 触发第一个动画,B 触发第二个动画。但是,当事件 A 再次触发时,MultiDataTrigger 似乎不再触发。为了增加混乱,B 的动画继续工作。只要事件在 A 和 B 之间交替,就会播放事件 B 动画,但不会播放事件 A。

<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>

发布的代码已经过简化,我从 MultiDataTrigger 中删除了第二个条件,因为它不会影响手头的问题。

我已经监控了 Tag 属性值,并且在事件触发时它被正确设置为 1 和 0。为什么触发器只会触发一次?或者,有没有更好的方法来解决这个问题?

【问题讨论】:

    标签: c# wpf


    【解决方案1】:

    我认为原因是您的故事板一直在运行。您应该在运行另一个故事板之前停止故事板。 看看这个答案:WPF Fade In / Out only runs once

    在另一件事上,我会说使用故事板来设置一个简单的值是一种矫枉过正的做法。考虑使用附加行为或 TriggerAction。 有关详细信息和示例,请参见此处:Setting a property with an EventTrigger

    【讨论】:

    • 正确!在 ExitAction 上停止故事板可以解决问题。
    【解决方案2】:

    原因是标签的值没有再次改变。 它是“1”,然后又是“1”。

    如果值未更改,则依赖属性不会运行任何回调。 我建议在设置“1”之前设置“0”,它什么都不做,然后为实际触发器设置“1”。

    希望对你有帮助

    【讨论】:

    • 当第二个事件触发时,标签的值被设置回 0。事件总是按 A -> B -> A -> ... 的顺序触发,因此 Tag 值应该在 1 和 0 之间切换(在 live property explorer 中对其进行监控可以确认这一点)。为了简化调试,我将事件触发器移到按钮上,以便手动控制它们。抱歉,如果我没有在问题中说明这一点。
    • @MrQuery 为什么它是 MultiDataTrigger 而不是 DataTrigger 我没有看到多个条件只有一个。而在什么情况下。如果您没有绑定到 DataContext 中的任何东西,为什么不使用 Trigger 而不是 DataTrigger。我之所以发表这些评论,是因为根据我的经验,WPF 并不完美,您应该找到在其中做某事的最小方法。例如,我从不使用多数据触发器,我只会创建一个复杂的属性,它将所有不同的属性组合在一个我知道效果很好的绑定下
    • 我正在尝试根据选择属性在为事件播放的动画之间切换。为了简化发布的代码,我删除了重新创建问题不需要的所有内容。在完整代码中,MultiDataTrigger 有一个附加条件。不管有没有这个,我仍然看到相同的行为。
    • Tier 是否引发 PropertyChanged 事件?
    • 没有。一般来说,一旦在启动时设置,Tier 的值在应用程序的整个生命周期中都不会改变。
    猜你喜欢
    • 1970-01-01
    • 2018-03-15
    • 2018-12-31
    • 1970-01-01
    • 2021-06-03
    • 1970-01-01
    • 2013-02-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多