7

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

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

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

这是自定义行为:

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以便在事件触发时启动动画。

干杯

4

1 回答 1

4

您可以简单地使用一个标志:在您的 VM 上设置一个名为“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");
    }
}

即,ChangedFlag = true当您想要启动动画时设置上面的代码。在 WPF 查询到 true 值后,它将被重置为 false。

然后让动画在值为RecentlyChangedFlagis时发生trueEnterAction例如。

希望有帮助。

于 2011-10-19T17:01:58.197 回答