【问题标题】:WPF and MVVM: Use RotateTransform and DoubleAnimation to move an object along circular pathWPF 和 MVVM:使用 RotateTransform 和 DoubleAnimation 沿圆形路径移动对象
【发布时间】:2022-02-03 08:07:10
【问题描述】:

我对 WPF 动画比较陌生。我想让一个对象(例如一个简单的圆圈)以 10 度的增量围绕圆形路径移动。以下示例非常接近:WPF circular moving object 请参阅 Clemens 的答案,他在 XAML 中使用 RotateTransform 并在代码隐藏中使用 DoubleAnimation。但是,我正在使用 MVVM,但我不清楚如何实现这一点。我相信我需要从我的 ViewModel 访问视图中的 RotateTransform,所以我可以调用 BeginAnimation,但是如何调用?

有什么例子或想法吗?我没有运气搜索过。 谢谢

更新:我现在可以通过展示我已经尝试过的内容来更具体地回答我的问题。基于上述参考和Twoway-bind view's DependencyProperty to viewmodel's property?(@Michael Schnerring 回答),我有以下简单代码(如下)。我的椭圆没有旋转。没有装订错误或任何其他错误,只是没有旋转。我的方法被击中(我调试了它)我猜我的 PerformAnimation 函数不正确,特别是 SetTargetProperty 部分。我确实尝试通过添加两个动画(一个用于旋转,一个用于变换)来玩它,但没有运气。

谁能告诉我我做错了什么?

XAML:

<Canvas Grid.Row="0" Grid.Column="0">
        <Ellipse Height="100" Width="100" Fill="Aqua" Name="MyEllipse"
         Canvas.Left="200" Canvas.Top="200"
         RenderTransformOrigin="0.5,0.5">
            <Ellipse.RenderTransform>
                <TransformGroup>
                    <TranslateTransform Y="-100"/>
                <RotateTransform />
                </TransformGroup>
            </Ellipse.RenderTransform>
        </Ellipse>
    </Canvas>

    <Button Grid.Row="0" Grid.Column="1" VerticalAlignment="Center" HorizontalAlignment="Center" Command="{Binding Path=RotateCommand}">Press Me!</Button>

代码隐藏

  public partial class MainWindow : Window
   {
      public MainWindow()
      {
         InitializeComponent();
         var nameOfPropertyInVm = "AngleProperty";
    var binding = new Binding(nameOfPropertyInVm) { Mode = BindingMode.TwoWay };
         this.SetBinding(AngleProperty, binding);
      }

      public double Angle
      {
         get { return (double)GetValue(AngleProperty); }
         set { SetValue(AngleProperty, value); }
      }

      // Using a DependencyProperty as the backing store for Angle.  This enables animation, styling, binding, etc...
      public static readonly DependencyProperty AngleProperty = DependencyProperty.Register("Angle", typeof(double), typeof(MainWindow), new UIPropertyMetadata(0.0, new PropertyChangedCallback(AngleChanged)));

      private static void AngleChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
      {
         MainWindow control = (MainWindow)sender;
         control.PerformAnimation((double)e.OldValue, (double)e.NewValue);
      }

      private void PerformAnimation(double oldValue, double newValue)
      {
         Storyboard s = new Storyboard();

         DoubleAnimation animation = new DoubleAnimation();
         animation.From = oldValue;
         animation.To = newValue;
         animation.Duration = new Duration(TimeSpan.FromSeconds(1));
         s.Children.Add(animation);

         
         Storyboard.SetTarget(animation, MyEllipse);
         Storyboard.SetTargetProperty(animation, new PropertyPath("(Ellipse.RenderTransform).(RotateTransform.Angle)"));

         s.Begin();

      }

和视图模型

    public class MyViewModel :  ViewModelBase
   {
      private ICommand _rotateCommand = null;
      private double _angleProperty = 10;
      public MyViewModel()
      {
         
      }

      public double AngleProperty
      {
         get
         {
            return _angleProperty;
         }

         set
         {
            _angleProperty = value;
            OnPropertyChanged("AngleProperty");
         }
      }

      public ICommand RotateCommand
      {
         get
         {
            if (_rotateCommand == null)
            {
               _rotateCommand = new RelayCommand(param => RotateCommandImplementation());
            }
            return _rotateCommand;
         }
      }

      private void RotateCommandImplementation()
      {
         AngleProperty = AngleProperty + 10;
      }
   }

【问题讨论】:

  • RotateTransform 的 Angle 属性可以绑定到视图模型中的属性。为了启动动画,应该有一个依赖属性(例如在 UserControl 或附加属性中)和启动动画的 PropertyChangedCallback。该属性将绑定到视图模型中的“目标角度”属性。
  • 感谢您的回复。根据您的评论,我几乎可以正常工作:)。也许因为它现在是一个直接的问题,并且我有示例代码,所以我可以简单地发布。我怀疑问题是我没有正确考虑 TranslateTransform 和 RotateTransform 。我对您的示例有些困惑 TranslateTransform Y="-100" 的作用,我会先尝试弄清楚这一点。慢慢到达那里。谢谢!
  • 更新问题以显示我已经尝试过的内容!
  • 我不明白你是如何设法介绍那个 Storybord 的。在我对另一个问题的回答中,有&lt;RotateTransform x:Name="rotateTransform"/&gt; 和rotateTransform.BeginAnimation(RotateTransform.AngleProperty, rotateAnimation);。请注意,"(Ellipse.RenderTransform).(RotateTransform.Angle)" 在此处不是有效的属性路径。它尝试在椭圆的 RenderTransform 中设置 RotateTransform 的角度。然而,RenderTransform 是一个 TransformGroup。你必须明白你在写什么,而不仅仅是从某个地方复制它并进行一些试验和错误。
  • 尤里卡!我知道了。显然我添加了 Storybord 只是为了让它更复杂:)。我把它拿出来清理干净。我会将我的代码作为答案发布,但无论如何,将您的 cmets 放入答案中,我会接受。我非常感谢您的帮助和耐心!现在唯一的问题(在我的情况下这不是特别的问题)是程序启动后椭圆会旋转一次 10 度。可能绑定正在发生,我点击了我的 PerformAnimation 代码。

标签: wpf mvvm rotatetransform doubleanimation


【解决方案1】:

这是我的解决方案,基于 @Clemens 的大量帮助(请参阅 cmets 和 WPF circular moving object)

查看

<Window x:Class="AnimationBindingPlay.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:AnimationBindingPlay"
    mc:Ignorable="d"
    Title="MainWindow" Height="450" Width="800">
<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*" />
        <ColumnDefinition Width="*" />
        <ColumnDefinition Width="*" />
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="*" />
        <RowDefinition Height="*" />
        <RowDefinition Height="*" />
    </Grid.RowDefinitions>
    <Canvas Grid.Row="0" Grid.Column="0">
        <Ellipse Height="100" Width="100" Fill="Aqua" Name="MyEllipse"
         Canvas.Left="200" Canvas.Top="200"
         RenderTransformOrigin="0.5,0.5">
            <Ellipse.RenderTransform>
                <TransformGroup>
                    <TranslateTransform Y="-100"/>
                    <RotateTransform x:Name="rotateTransform"/>
                </TransformGroup>
            </Ellipse.RenderTransform>
        </Ellipse>
    </Canvas>

    <Button Grid.Row="0" Grid.Column="1" VerticalAlignment="Center" HorizontalAlignment="Center" Command="{Binding Path=RotateCommand}">Press Me!</Button>
    
</Grid>

后面的代码

 public partial class MainWindow : Window
   {
      public MainWindow()
      {
         InitializeComponent();
         var nameOfPropertyInVm = "AngleProperty";
         var binding = new Binding(nameOfPropertyInVm) { Mode = BindingMode.TwoWay };
         this.SetBinding(AngleProperty, binding);
      }

      public double Angle
      {
         get { return (double)GetValue(AngleProperty); }
         set { SetValue(AngleProperty, value); }
      }

      // Using a DependencyProperty as the backing store for Angle.  This enables animation, styling, binding, etc...
      public static readonly DependencyProperty AngleProperty = DependencyProperty.Register("Angle", typeof(double), typeof(MainWindow), new UIPropertyMetadata(0.0, new PropertyChangedCallback(AngleChanged)));

      private static void AngleChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
      {
         MainWindow control = (MainWindow)sender;
         control.PerformAnimation((double)e.OldValue, (double)e.NewValue);
      }

      private void PerformAnimation(double oldValue, double newValue)
      {
       
         var rotationAnimation = new DoubleAnimation(oldValue, newValue, TimeSpan.FromSeconds(1));
         rotateTransform.BeginAnimation(RotateTransform.AngleProperty, rotationAnimation);

      }

   }

视图模型 与问题相同!

【讨论】:

    猜你喜欢
    • 2016-08-25
    • 1970-01-01
    • 1970-01-01
    • 2016-09-22
    • 1970-01-01
    • 2011-09-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多