Как плавно анимировать значение связанного свойства из его старого значения в его новое значение в WPF

#wpf #xaml

#wpf #xaml

Вопрос:

Как мне плавно анимировать предыдущее значение связанного свойства в его новое значение?

Допустим, у нас есть следующий холст и строка.

 <Canvas>
    <Line 
        Canvas.Top="0"
        Stroke="#887FFF00"
        StrokeThickness="2"
        X1="0" Y1="0"
        X2="0" Y2="{Binding ActualHeight, RelativeSource={RelativeSource AncestorType=Canvas}}"
        Canvas.Left="{Binding Position}"
        >
    </Line>
</Canvas>
  

Горизонтальное положение строки определяется свойством Position, привязанным к Canvas.Оставлено присоединенное свойство. Когда позиция изменяется, скажем, со 100 на 200, я хотел бы анимировать положение строки из ее предыдущего значения плавно в ее новое значение.

Как мне это сделать?

Ответ №1:

Безусловно, самый простой способ плавно анимировать свойство в wpf — это использовать анимацию.

Однако для ваших требований в анимации есть несколько хитрых моментов.

Вы не можете привязать «from» или «to» к анимации, поэтому для этого потребуется создать анимацию в коде.

Для анимации значения вам нужно свойство dependency и, следовательно, объект dependency.

Вы могли бы рассмотреть возможность создания viewmodel, который предоставляет position, в объект зависимости. Затем вы можете создать новую анимацию в коде, когда вам нужно ее анимировать, и просто сохранить там свою привязку.

Или… вы могли бы определить раскадровку как ресурс и изменить это в коде для создания вашей анимации.

Вот так https://social.technet.microsoft.com/wiki/contents/articles/31191.wpf-tips-animating-a-viewmodel.aspx

Возможно, вам не нравится делать viewmodel объектом зависимости.

Если вас устраивает немного «скрытого кода» в вашем представлении, то это объект зависимости. Вы могли бы в качестве альтернативы добавить свойство зависимости в свое окно. Привяжите это к Position, а затем анимируйте canvas.слева от вашей строки или другого свойства зависимости, к которому привязана строка.

Ответ №2:

Вместо прямой привязки к исходному свойству с использованием {Binding} синтаксиса в XAML, вы могли бы самостоятельно подписаться на PropertyChanged событие модели представления в представлении и анимировать свойство программно, например:

 private void OnViewLoaded(object sender, RoutedEventArgs e)
{
    ViewModel viewModel = DataContext as ViewModel;
    if (viewModel != null)
    {
        Canvas.SetLeft(line, viewModel.Position);
        viewModel.PropertyChanged  = OnPropertyChanged;
    }
}

private void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
{
    if (e.PropertyName == "Position")
    {
        double from = Canvas.GetLeft(line);
        if (double.IsNaN(from))
            from = 0;
        ViewModel viewModel = sender as ViewModel;
        if (viewModel != null)
        {
            DoubleAnimation doubleAnimation = new DoubleAnimation()
            {
                From = from,
                To = viewModel.Position,
                Duration = TimeSpan.FromSeconds(1)
            };
            line.BeginAnimation(Canvas.LeftProperty, doubleAnimation);
        }
    }
}
  

XAML:

 <Canvas Width="100" Height="100" Background="Beige">
<Line x:Name="line"
        Canvas.Top="0"
        Stroke="#887FFF00"
        StrokeThickness="2"
        X1="0" Y1="0"
        X2="0" Y2="{Binding ActualHeight, RelativeSource={RelativeSource AncestorType=Canvas}}">
</Line>
</Canvas>
  

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