Запуск анимации из события с использованием MVVM - PullRequest
7 голосов
/ 19 октября 2011

Я, кажется, достиг какой-то критической точки MVVM здесь.

Я бы хотел, чтобы у элемента управления была анимация его непрозрачности на полсекунды (DoubleAnimation от 0,5 до 1,0), когда базовый объект модели представления изменил свое свойство Status. Я достиг этого вначале, используя DataTrigger, но так как я не нашел способа реагировать на ЛЮБОЕ изменение, только на заданное значение, мне пришлось всегда переключать свойство «Состояние» объектов ВМ на специальное «ожидающее» значение, прежде чем устанавливать его к его предполагаемой стоимости. (Есть ли способ реагировать на любые изменения между прочим?)

Это было нахально, поэтому я начал возиться с 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, чтобы запустить анимацию при возникновении события.

Приветствия

1 Ответ

4 голосов
/ 19 октября 2011

Вы можете просто использовать флаг: установите флаг на вашей виртуальной машине, который называется '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, когда вы хотите подать сигнал на запуск анимации. Он будет сброшен в false после того, как WPF запросит истинное значение.

Затем анимация возникает, когда значение RecentlyChangedFlag равно true, например EnterAction.

Надеюсь, это поможет.

...