使用MVVM从事件触发动画

时间:2011-10-19 16:59:40

标签: wpf events animation eventtrigger

我似乎已经达到了某种MVVM的突破点。

当底层视图模型对象的“Status”属性发生变化时,我希望控件的不透明度动画半秒(DoubleAnimation从0.5到1.0)。我最初使用DataTrigger实现了这一点,但由于我没有找到对任何更改作出反应的方法,只是一个给定的值,我必须始终在设置它之前将VM对象“Status”属性翻转为特殊的“pending”值达到预期的价值。 (有没有办法对任何改变做出反应?)

这很hacky所以我开始摆弄EventTriggers而不是......

这是我到目前为止所尝试的:

  1. 使用普通EventTrigger
  2. 这似乎需要一个RoutedEvent但反过来要求我的底层视图模型对象继承自DependencyObject。

    1. 使用i:Interaction.Triggers
    2. 这样我就可以听取正常的.NET事件并做出反应,但我还没有找到一种方法来使用这种方法启动StoryBoard

      1. 使用i:Interaction.Triggers并撰写Behavior
      2. 这个实验没有找到我无法将自定义行为附加到其关联控件的事实。

        这就是XAML的样子:

           <cc:MyControl>
                <i:Interaction.Triggers>
                    <i:EventTrigger EventName="Updated">
                        <i:Interaction.Behaviors>
                            <cv:OpacityBehavior Duration="0:0:0:5" />
                        </i:Interaction.Behaviors>
                    </i:EventTrigger>
                </i:Interaction.Triggers>
        

        这是自定义行为:

        class OpacityBehavior : Behavior<MyControl>
        {
            public Duration Duration { get; set; }
        
            protected override void OnAttached()
            {
                base.OnAttached();
                var animation = new DoubleAnimation(0.5, 1, Duration, FillBehavior.HoldEnd);
                var associatedObject = lookupVisualParent(this);
                associatedObject.BeginAnimation(UIElement.OpacityProperty, animation);
            }
        }
        

        这不起作用,因为XAML解析器要求它直接附加到“MyControl”,但我需要将它附加到事件触发器。然后我尝试了这种方法:

        class OpacityBehavior : Behavior<DependencyObject>
        {
            public Duration Duration { get; set; }
        
            protected override void OnAttached()
            {
                base.OnAttached();
                var animation = new DoubleAnimation(0.5, 1, Duration, FillBehavior.HoldEnd);
                var associatedObject = lookupVisualParent(this);
                associatedObject.BeginAnimation(UIElement.OpacityProperty, animation);
            }
        
            private UIElement lookupVisualParent(DependencyObject dObj)
            {
                if (dObj is UIElement)
                    return (UIElement) dObj;
        
                if (dObj == null)
                    return null;
        
                return lookupVisualParent(LogicalTreeHelper.GetParent(dObj));
            }
        }
        

        由于lookupVisualParent不起作用,这失败了。行为的逻辑父级始终为null

        这对我来说这应该是一项相当普遍的任务吗?这个问题有一个很好的解决方案吗?我觉得奇怪的是,我将编写我的视图模型类,以便它们派生自DependencyObject,以便在事件触发时启动动画。

        干杯

1 个答案:

答案 0 :(得分:4)

你可以简单地使用一个标志:在你的VM上设置一个名为'RecentChangedFlag'的标志。每当适当的值发生变化时,将其脉冲为true,然后false。你可以这样做:

private bool _changedFlag;
public bool ChangedFlag
{
    get
    {
        if (_changedFlag)
        {
            _changedFlag = false;
            OnPropertyChanged("ChangedFlag");
            return true;
        }
        // (else...)
        return false;
    }
    protected set
    {
        _changedFlag = value;
        OnPropertyChanged("ChangedFlag");
    }
}

即,当您想要通知动画开始时,使用上面的代码集ChangedFlag = true。在WPF查询真值后,它将被重置为false。

然后,当RecentlyChangedFlag的值为true时,动画就会出现,例如EnterAction

希望有所帮助。