Как лучше всего запустить анимацию при изменении связанного значения?

StackOverflow https://stackoverflow.com/questions/1122177

Вопрос

Часто возникает такая ситуация:

В представлении у вас есть элемент управления, привязанный к свойству ViewModel (поддерживаемый INotifyPropertyChanged).Например:

<TextBlock Text="{Binding Path=Subtotal}"/>

Когда свойство меняется, вам необходимо привлечь внимание пользователя к этому факту с помощью креативной анимации.Как я могу использовать тот факт, что представление уже подключено к уведомлению, и избежать создания большей части дополнительного кода (или, по крайней мере, создать его один раз и использовать повторно).Триггеры данных, вероятно, являются лучшим выбором, но я не знаю, как заставить их срабатывать при любом изменении значения, а не при каком-то конкретном значении.

На ум приходят следующие варианты:

  • вызовите дополнительное событие во ViewModel, подпишитесь на код программной части View.
  • создайте триггер данных, привязанный к упомянутому свойству, с помощью преобразователя, который будет возвращать true, если значение меняется.
  • создайте триггер данных, привязанный к новому логическому свойству ViewModel, которое используется для «сигнализации» об изменении.
  • создайте поведение, прикрепленное к элементу управления, которое будет подписываться на изменение свойства зависимостей элемента управления и запускать анимацию.

Какой из них вам нравится/используется?Я пропустил какие-то варианты?

P.S.Было бы хорошо (но не критично), если бы решение обеспечивало возможность сначала запускать анимацию и отражать изменение значения после ее завершения.

Это было полезно?

Решение

Хорошо, вот к чему я пришел после некоторых экспериментов.

Я создал триггер Expression Blend 3 со свойством зависимости (я назвал его «Подписка»).Я привязываю подписку к тому же значению, к которому привязан мой TextBlock, и этот триггер прикреплен к ControlStoryboardAction из Expression Blend 3.

Вот триггер:

public class DataTriggerPlus : TriggerBase<DependencyObject>
{
    public static readonly DependencyProperty SubscriptionProperty =
        DependencyProperty.Register("Subscription", 
            typeof(string),
            typeof(DataTriggerPlus),
            new FrameworkPropertyMetadata("",
              new PropertyChangedCallback(OnSubscriptionChanged)));

    public string Subscription
    {
        get { return (string)GetValue(SubscriptionProperty); }
        set { SetValue(SubscriptionProperty, value); }
    }

    private static void OnSubscriptionChanged(DependencyObject d,
      DependencyPropertyChangedEventArgs e)
    {
        ((DataTriggerPlus)d).InvokeActions(null);
    }
}

Вот как он прикреплен к раскадровке:

<TextBlock x:Name="textBlock" Text="{Binding TestProp}" Background="White">
    <i:Interaction.Triggers>
        <local:DataTriggerPlus Subscription="{Binding TestProp}">
            <im:ControlStoryboardAction 
                Storyboard="{StaticResource Storyboard1}"/>
        </local:DataTriggerPlus>
    </i:Interaction.Triggers>
</TextBlock>

Мне очень нравится этот подход, отличная работа дизайнеров Blend 3!

Редактировать:отвечаю на комментарий Дрю...

Да, он поставляется с Blend.Вы можете просто включить Microsoft.Expression.Interactions.dll и System.Windows.Interactivity в свой проект.

И да, это многословно (я спросил, нашел ли кто-нибудь хороший способ применить поведение через стили в этом вопросе) - но есть и преимущество гибкости.Например, вы можете не только запустить раскадровку, но и переключить состояние или выполнить какое-либо другое действие с помощью того же триггера.

Другие советы

Вы можете создать триггер, который запустит анимацию.

Что-то вроде этого:

<Style>
    <Style.Triggers>
       <Trigger 
            Property="ViewModelProperty"
            Value="True">
            <Trigger.EnterActions>
                 <BeginStoryboard Storyboard="YourStoryBoard" />
            </Trigger.EnterActions>
       </Trigger>
    </Style.Triggers>
</Style>

Что касается проблемы с установкой значения после завершения анимации, это немного неприятно.Насколько я знаю, вам нужно будет использовать завершенное событие в раскадровке, для этого требуется код, чего вы хотите избежать с помощью MVVM.

Я пробовал использовать EventTriggers для привязки к завершенным событиям, но это также создает некоторые сложности.Видеть здесь Больше подробностей.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top