使用MVVM从事件触发动画

Jon*_*att 7 wpf events animation eventtrigger

我似乎在这里达到了某种MVVM的突破点.

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

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

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

  1. 使用正常 EventTrigger

这似乎需要一个RoutedEvent但反过来要求我的底层视图模型对象继承自DependencyObject.

  1. 运用 i:Interaction.Triggers

这样我就可以听取并对正常的.NET事件做出反应,但我还没有找到一种方法来开始StoryBoard使用这种方法.

  1. 使用i:Interaction.Triggers和写作Behavior

这个实验没有找到我无法将自定义行为附加到其关联控件的事实.

这就是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>
Run Code Online (Sandbox Code Playgroud)

这是自定义行为:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

这不起作用,因为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));
    }
}
Run Code Online (Sandbox Code Playgroud)

这失败的事实是lookupVisualParent不起作用.行为的逻辑父对象始终是null.

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

干杯

Kie*_*one 4

您可以简单地使用一个标志:在虚拟机上设置一个名为“RecentlyChangedFlag”的标志。每当适当的值发生变化时,将其脉冲至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");
    }
}
Run Code Online (Sandbox Code Playgroud)

ChangedFlag = true即,当您想要发出动画开始信号时,使用上面的代码设置。WPF 查询 true 值后会重置为 false。

例如,然后当RecentlyChangedFlag的值为 时发生动画。trueEnterAction

希望有帮助。

  • 我不会对此抱有虔诚的态度,但似乎很奇怪,不可能从事件中触发动画。毕竟,事件是用来表示状态变化的。恕我直言,必须添加第二个属性只是为了向第一个属性发出状态更改信号是一种解决方法。我很惊讶地发现 WPF 提供的工具有如此的缺陷。在这种特殊情况下,我当然可以接受“状态属性解决方案”,但我预计我的 VM 类将来将充满此类属性。一定有更好的方法,对吧? (4认同)