带有情节提要的数据触发器未触发

Datatrigger with Storyboard not firing

我在同一个图像上有 5 个不同的 DataTriggers,每个都用于相同的绑定但具有不同的值,每个都将图像旋转不同的角度。 每次更改值后,该值都会重置为 0。

当我没有添加 DataTrigger.ExitActions> <RemoveStoryboard> 东西时它们工作了一次,但它们只工作了一次,所以如果 steps 绑定再次获得这个值,它们就不会触发。

<Image x:Name="drehteller" HorizontalAlignment="Center" VerticalAlignment="Center" RenderTransformOrigin="0.5,0.5" Source="{Binding drehteller_image}">
        <Image.RenderTransform>
            <RotateTransform/>
        </Image.RenderTransform>
        <Image.Style>
            <Style>
                <Style.Triggers>
                    <DataTrigger Binding="{Binding steps}" Value="1">
                        <DataTrigger.EnterActions>
                            <BeginStoryboard x:Name="Storyboard1Step">
                                <Storyboard>
                                    <DoubleAnimation
                                        Storyboard.TargetProperty="RenderTransform.Angle" 
                                        By="72"
                                        Duration="00:00:00:03"
                                    />
                                </Storyboard>
                            </BeginStoryboard>
                        </DataTrigger.EnterActions>
                        <DataTrigger.ExitActions>
                            <RemoveStoryboard BeginStoryboardName="Storyboard1Step"/>
                        </DataTrigger.ExitActions>
                    </DataTrigger>
                    <DataTrigger Binding="{Binding steps}" Value="2">
                        <DataTrigger.EnterActions>
                            <BeginStoryboard x:Name="Storyboard2Step">
                                <Storyboard>
                                    <DoubleAnimation
                                        Storyboard.TargetProperty="RenderTransform.Angle" 
                                        By="144"
                                        Duration="00:00:00:03"
                                    />
                                </Storyboard>
                            </BeginStoryboard>
                        </DataTrigger.EnterActions>
                        <DataTrigger.ExitActions>
                            <RemoveStoryboard BeginStoryboardName="Storyboard2Step"/>
                        </DataTrigger.ExitActions>
                    </DataTrigger>
                    <DataTrigger Binding="{Binding steps}" Value="3">
                        <DataTrigger.EnterActions>
                            <BeginStoryboard x:Name="Storyboard3Step">
                                <Storyboard>
                                    <DoubleAnimation
                                        Storyboard.TargetProperty="RenderTransform.Angle" 
                                        By="216"
                                        Duration="00:00:00:03"
                                    />
                                </Storyboard>
                            </BeginStoryboard>
                        </DataTrigger.EnterActions>
                        <DataTrigger.ExitActions>
                            <RemoveStoryboard BeginStoryboardName="Storyboard3Step"/>
                        </DataTrigger.ExitActions>
                    </DataTrigger>
                    <DataTrigger Binding="{Binding steps}" Value="4">
                        <DataTrigger.EnterActions>
                            <BeginStoryboard x:Name="Storyboard4Step">
                                <Storyboard>
                                    <DoubleAnimation
                                        Storyboard.TargetProperty="RenderTransform.Angle" 
                                        By="72"
                                        Duration="00:00:00:03"
                                    />
                                </Storyboard>
                            </BeginStoryboard>
                        </DataTrigger.EnterActions>
                        <DataTrigger.ExitActions>
                            <RemoveStoryboard BeginStoryboardName="Storyboard4Step"/>
                        </DataTrigger.ExitActions>
                    </DataTrigger>
                    <DataTrigger Binding="{Binding steps}" Value="5">
                        <DataTrigger.EnterActions>
                            <BeginStoryboard x:Name="Storyboard5Step">
                                <Storyboard>
                                    <DoubleAnimation
                                        Storyboard.TargetProperty="RenderTransform.Angle" 
                                        By="360"
                                        Duration="00:00:00:03"
                                    />
                                </Storyboard>
                            </BeginStoryboard>
                        </DataTrigger.EnterActions>
                        <DataTrigger.ExitActions>
                            <RemoveStoryboard BeginStoryboardName="Storyboard5Step"/>
                        </DataTrigger.ExitActions>
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </Image.Style>
    </Image>

也许有人知道我做错了什么,我认为 RemoveStoryboard 可能会解决他们只触发一个的问题,但看起来他们没有。

编辑:发现如果没有 ExitActions 我可以随心所欲地触发值为 1 的触发器,只要值永远不会高于 1,所以如果我一次触发值为 1 的触发器2,值为 1 的触发器将不再工作,如果我触发值为 3 的触发器,则值为 2 的触发器将不再工作。等等,我猜你明白了。

一个非常简单直接的解决方案是 运行 隐藏代码中的动画:

var viewModel = new ViewModel();

viewModel.PropertyChanged += (s, e) =>
{
    if (e.PropertyName == nameof(viewModel.Steps))
    {
        drehteller.RenderTransform.BeginAnimation(
            RotateTransform.AngleProperty,
            new DoubleAnimation
            {
                By = viewModel.Steps * 72,
                Duration = TimeSpan.FromSeconds(3)
            });
    }
};

DataContext = viewModel;

这与 MVVM 并不矛盾,因为视图模型仍然对视图一无所知。这是一个纯视图方面。

您也可以使用 attached behavior 执行此操作。这些是一些可重用的视图逻辑,您可以将它们附加到各种 UI 元素,而无需将它们放在代码隐藏中。

您需要 Microsoft.Xaml.Behaviors.Wpf NuGet package(这曾经作为 Visual Studio 的 "Blend for Visual Studio SDK for .NET" 组件的一部分分发,但这在 VS 2019 中发生了变化)。

定义你的行为。请注意,AssociatedObject 指的是与此行为关联的 Image,请参见下文。

public class AnimateBehavior : Behavior<Image>
{
    public int Steps
    {
        get => (int)GetValue(StepsProperty);
        set => SetValue(StepsProperty, value);
    }
    public static readonly DependencyProperty StepsProperty =
        DependencyProperty.Register(nameof(Steps), typeof(int), typeof(AnimateBehavior), new PropertyMetadata(0, (d, e) => ((AnimateBehavior)d).StepsChanged(e)));

    private void StepsChanged(DependencyPropertyChangedEventArgs e)
    {
        if (AssociatedObject == null)
            return;

        AssociatedObject.RenderTransform.BeginAnimation(
            RotateTransform.AngleProperty,
            new DoubleAnimation()
            {
                By = (int)e.NewValue * 72,
                Duration = TimeSpan.FromSeconds(3),
            });
    }
}

然后在您的 XAML 中,您将需要此命名空间:

xmlns:behaviors="http://schemas.microsoft.com/xaml/behaviors"

然后:

<Image ...>
    <Image.RenderTransform>
        <RotateTransform/>
    </Image.RenderTransform>
    <behaviors:Interaction.Behaviors>
        <local:AnimateBehavior Steps="{Binding steps}"/>
    </behaviors:Interaction.Behaviors>
</Image>