WPF MVVM模式下动画的实现

2021-01-17 00:14

阅读:520

标签:key   ble   操作   简单的   绑定   一个   width   mvvm   oct   

原文:WPF MVVM模式下动画的实现

在MVVM模式下,数据的显示都是通过绑定来实现的。当我们在ViewModel里修改数据时,View里面的界面会瞬间变化。但是如果我们希望这个变化有一个动画效果,应该怎么做呢?

可能一开始我们会想到DoubleAnimation、StoryBoard这些东西,但我们很快就会发现,它们只能操作View里面的元素,我们无法在ViewModel里使用它们。

我们在这里使用的方法是:创建一个类似DoubleAnimation的类,它的操作对象就是普通的double类型。在某一个时间段内,double类型的属性连续变化,View里的元素也会显示出一个动画的效果。

首先我们在View里放一个小正方形:

  1. Rectangle Width="10" Height="10" Fill="Red" Canvas.Left="{Binding RectLeft}"/>
  2. Canvas>

我们看到,正方形的Canvas.Left属性绑定了一个名为RectLeft的属性。而ViewModel也相当简单:

  1. [ImplementPropertyChanged]
  2. public class ViewModel
  3. {
  4. public double RectLeft { get; set; }
  5. }

我们这里用到了Fody.PropertyChanged,所以不用写RaisePropertyChanged那些代码。相关的资料可到百度上搜索。

好了,我们现在只要在某个时间段内,让RectLeft从一个值缓缓地变到另一个值,小正方形就会动起来了。

我们新建一个同样名叫DoubleAnimation的自定义类,然后我们这样来使用它:

  1. DoubleAnimation ani = new DoubleAnimation(10, 700, 1000, (v) =>
  2. {
  3. RectLeft = v;
  4. });
  5. ani.BeginAnimation();

第一个参数是From,第二个参数是To,第三个参数是时间,第四个参数是一个委托,用来改变RectLeft的值。由于RectLeft是一个属性,我们没办法用ref标记把它作为引用参数,只能用这种方法去改变它。

好了,我们现在就来看DoubleAnimation的实现,上代码:

  1. public class DoubleAnimation
  2. {
  3. ///
  4. /// 最小时间单元
  5. ///
  6. private const int MinTimeUnit = 40;
  7. private int Segments;
  8. private double[] MidValues;
  9. ///
  10. /// 构造DoubleAnimation
  11. ///
  12. /// 起始点
  13. /// 结束点
  14. /// 周期,单位毫秒
  15. /// 设值函数
  16. public DoubleAnimation(double from, double to, int interval, Actiondouble> setvalue)
  17. {
  18. From = from;
  19. To = to;
  20. Interval = interval;
  21. SetValue = setvalue;
  22. }
  23. ///
  24. /// 起始点
  25. ///
  26. private double From { get; set; }
  27. ///
  28. /// 结束点
  29. ///
  30. private double To { get; set; }
  31. ///
  32. /// 周期,单位毫秒
  33. ///
  34. private int Interval { get; set; }
  35. ///
  36. /// 设值函数
  37. ///
  38. private Actiondouble> SetValue;
  39. ///
  40. /// 完成函数
  41. ///
  42. public Action Completed;
  43. ///
  44. /// 缓动方法
  45. ///
  46. public EasingMethod EasingMethod { get; set; } = EasingMethod.Linear;
  47. ///
  48. /// 开始动画
  49. ///
  50. public void BeginAnimation()
  51. {
  52. Segments = Interval / MinTimeUnit;
  53. if (Segments == 0)
  54. {
  55. Segments = 1;
  56. }
  57. MidValues = new double[Segments + 1];
  58. MidValues[0] = From;
  59. MidValues[Segments] = To;
  60. CalcMidValues();
  61. new Thread(() =>
  62. {
  63. for (int i = 0; i
  64. {
  65. SetValue(MidValues[i]);
  66. Thread.Sleep(MinTimeUnit);
  67. }
  68. SetValue(MidValues[Segments]);
  69. Completed?.Invoke();
  70. }).Start();
  71. }
  72. ///
  73. /// 计算中间值
  74. ///
  75. private void CalcMidValues()
  76. {
  77. if (EasingMethod == EasingMethod.Linear)
  78. {
  79. double gap = (To - From) / Segments;
  80. double current = From;
  81. for (int i = 1; i
  82. {
  83. current += gap;
  84. MidValues[i] = current;
  85. }
  86. }
  87. }
  88. }
  89. 代码其实很简单,我们分步骤看:

    (1)我们设置好起点From、终点To,时间Interval。

    (2)我们知道,1/24秒是一般电影的帧率,也就是差不多40ms一帧,在这个频率下,人眼会觉得动画是连续的。

    (3)我们把总时间进行分段,例如是1s,这里面应该有1000/40=25段,端点就是26个。我们计算出26个端点的值。

    (4)最普遍也最简单的计算就是线性插值了。我们知道,.NET里面的Animation提供了大量的EasingFunction,它们的作用就是在这里插值用的。这个日后可以完善,慢慢加到类里面。

    (5)好了,最重要的一步,就是不断地改变RectLeft的值。在这里,我们是40ms改变一次。可以考虑使用定时器或是线程来做,我们这里用线程去做。代码确实简单,就是一个for循环,改变一次值之后,“睡”40ms。完了之后如果有需要的,可以调用一个Completed的事件。

    WPF MVVM模式下动画的实现

    标签:key   ble   操作   简单的   绑定   一个   width   mvvm   oct   

    原文地址:https://www.cnblogs.com/lonelyxmas/p/12208791.html

上一篇:WPF 3D开发教程(三)

下一篇:WPF 3D开发教程(二)


评论


亲,登录后才可以留言!

热门文章

推荐文章

最新文章

置顶文章