【问题标题】:Datatrigger with Storyboard not firing带有情节提要的数据触发器未触发
【发布时间】:2020-01-01 09:19:07
【问题描述】:

我在同一个图像上有 5 个不同的 DataTrigger,每个都用于相同的绑定但具有不同的值,每个都将图像旋转不同的角度。 每次更改值后,值都会重置为 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 的触发器,因此,如果我曾经触发值为 2 的触发器,则触发器值为 1 的触发器将不再起作用,如果我触发值为 3 的触发器,则值为 2 的触发器将不再起作用。等等,猜你明白了。

【问题讨论】:

  • StopStoryboard 代替 RemoveStoryboard?
  • 这在后面的代码中实现起来会容易得多。
  • @Clemens 但我在 MVVM 中编码,不允许使用后面的代码,但我需要使用 VM
  • MVVM 允许您使用附加行为和附加属性。像这样的东西在附加行为中可能会很好地工作 - 它为您提供代码隐藏的所有功能,但以更加模块化和可重用的方式。
  • 这是一个常见的误解。 MVVM 并不意味着您的视图不能有任何代码。当然,您仍然可以使用带有 steps 属性的相同视图模型,但不是数据绑定,而是手动附加一个启动动画的 PropertyChanged 事件处理程序。

标签: c# wpf storyboard datatrigger


【解决方案1】:

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

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 并不矛盾,因为视图模型仍然对视图一无所知。这是一个纯粹的视图方面。

【讨论】:

    【解决方案2】:

    您也可以使用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>
    

    【讨论】:

      猜你喜欢
      • 2012-04-27
      • 2023-03-21
      • 2017-10-28
      • 2021-03-25
      • 2018-08-06
      • 1970-01-01
      • 2011-07-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多