WPF“动画序列”框架的初步研究与实现(附源码)

简介:

摘要:相对以往的界面编程框架来说,WPF引入了很多激动人心的特性。对动画的抽象就是这些特性之一。但这并不意味着WPF的动画框架就已经很完美了。WPF利用Storyboard表示动画,通过在Storyboard中动态改变依赖属性的值,从而实现相应的动画效果。但是Storyboard有其本身的局限。其局限之一就是难以表示动画序列。本文对这个问题进行了探讨,在讨论了Storyboard局限的同时,给出了一个动画序列框架的初步实现。实验证明,这个框架在原有的动画基础上引入了序列的机制,可以更好地表示动画。在此基础上,完全可以对该框架进行扩展,使得其成为通用性的框架,在WPF/Silverlight中得到广泛的应用。

 

“飞刀,又见飞刀……” –引自古龙同名小说

“动画,又见动画……”  –引自作者的梦话

0.       背景

好吧,我不得不说,虽然接触不久,但我真的迷上WPF了。与以往的界面框架相比,WPF确实改变了很多,从逻辑树到依赖属性,从路由事件到模板……,这些功能极大地丰富了界面开发的方法。但在所有的这些特性中,最令我魂牵梦萦的,还是动画。

是的,就是动画。WPF对动画进行了抽象,将动画与依赖属性绑在了一起。同时提供了Storyboard,这样,我们就可以很容易地动态修改依赖属性值,从而实现动画。动画实现变得容易了,带来的好处就是我们可以花费较少的工作量在程序中引入更丰富的动画,使得程序变得更酷——这是不言而喻的。甚至可以说,没有动画,WPF炫丽的界面就会黯然失色。而善于使用动画也是WPF程序设计者不可或缺的能力之一。

正是基于这样的背景,我在说梦话被老婆打醒后,决定认真研究一下动画。试着实现一些动画效果。

1.       问题描述

在实现了几个基本的动画效果之后,我遇到了一个问题:Storyboard不擅长表示动画序列。所谓动画序列呢,额……就是动画组成序列啦。就是我先播放一个动画,等到前一个动画播放完毕后再播放下一个动画,依此类推。

动画序列很有用。比如在视图转换的过程中,我们希望实现如下的动画:将当前的视图变小,变小到一定程度后从屏幕中移除,从而露出后面的动画。这本质上是一个动画序列,包含了两个动画。第一个动画减小视图尺寸,第二个动画移除减少尺寸后的视图。两个动画依次执行。还可以用动画序列实现很多功能,只要我们的想象力够丰富就可以。

用Storyboard也可以实现动画序列。在Storyboard中定义动画时,可以为一些动画(比如DoubleAnimation)指定开始时间。只要确保后一个动画的开始时间是前一个动画的终止时间,就能实现这个功能了。但这种实现方式有其自身的缺陷——代码复杂,不便于维护。所以我说Storyboard不擅长表示动画序列。为了给大家一个实际的感受,让我们看一个例子:

假设目前有一个按钮,单击按钮时,我们希望按钮首先变宽;变化完成后再变高;之后宽与高统一缩小;最后宽与高统一扩大一点。

这是一个典型的动画序列。为了用Storyboard实现这个功能,我们可以在XAML中引入如下的定义(可以在所附代码的OriginalMethod项目中找到相关的代码):

其中的“_btn”是动画将要实施的按钮。

不管你晕不晕,反正我看到上面的代码是晕了。这段代码非常不好,原因如下:

l  首先,在设置每个动画的BeginTime时,很容易设置错误(事实上,作者在写这段代码时,就出现了设置错误,导致动画效果不符合预期);

l  其次,这段代码没有层次感,一眼看上去,很难看清楚这段代码实际上定义了4段动画;

l  第三,这段代码难以修改:如果我们希望改变某段动画持续的时间,那么它后面所有的动画所持续的时间都需要发生变化;而且,如果我们希望改变动画的顺序,那么相应的每个动画的BeginTime可能都要发生改变。当引入的动画段落比较多时,这种方式很容易引入错误。

正是由于上述原因,我得出了“Storyboard”不擅长表示动画这个结论。

2. 动画序列的表示框架

为了解决上述问题,我设计并初步实现了一个动画序列。调用动画序列的代码所示(可以在本文所附代码中找到完成的示例):

这个代码实现了上述4段的动画。从代码中可以看出,使用动画序列,我们可以:

l  免除BeginTime的设置,减少出错的可能性;

l  代码更加易读:从代码中可以一目了然地看到其中包含的动画段数以及动画的执行顺序;

l  代码便于修改:对每个单独动画的调整,只需在相应的Storyboard中修改即可;对动画顺序的调整,则只需要调整Storyboard的顺序即可,无需其它的操作;

l  新的类可以与XAML之间较好的集成。

3. 动画序列框架的实现

这一部分讨论这个框架的实现方法。

为了实现序列的功能,我首先定义了一个序列类StoryboardChain,并在其中引入了属性:

用于包含Storyboard序列。

这个类同时包含了一个Begin方法,用于调用动画。这个方法的主要代码如下:

代码会遍历现有的Storyboard集合,通过ElementIndexer.SetPos为每一个Storyboard引入一个附加属性,这个附加属性用于表示当前动画执行完毕后,下一个动画的ID。对于集合中的最后一个动画,这个值为-1,表示没有后续需要执行的内容了。在此基础上,为每个Storyboard的Completed事件关联一个句柄OnCurrentFinished。当前动画执行完毕后,系统会调用这个函数,执行下一个动画。这些都设置完毕后,调用第一个Storyboard的Begin方法,开始整个动画序列的执行。

OnCurrentFinished则主要用于调用下一个动画,其主要代码如下所示:

这就将整个动画串起来了。

最后,我们需要为该类添加一个特性声明:

这样,在XAML中声明的Storyboard将被置于Animates中。

OK,大功告成!。现在就可以测试一下这个序列了。测试的代码也包含在附带的源码中。

4. 小结

在发现Storyboard表示动画序列差强人意后,为了能够用更丰富地方法表示动画,我实现了一个“动画序列”的基础框架:实现了基本的动画序列的功能。与仅仅采用Storyboard表示动画序列相比,使用这个框架可以也出更易懂,更便于维护的代码。

之所以说这个框架是一个“基础框架”,因为它还有很多可以改进的地方,比如:

l  StoryboardChain中只包含了Begin方法,在实际使用中,可能需要中断动画的方法;

l  从上面的代码中可以看到,StoryboardChain中的每个Storyboard均需要设定TargetName,如果这些名称相同,可以考虑在StoryboardChain中进行设置,而不是针对每个Storyboard设置;

l  StoryboardChain目前不能控制动画执行的总体时间:动画执行的总体时间是由每个Storyboard执行的时间求和得到的,可以考虑引入类似Grid的机制,使用“1*”等方式在Storyboard中设置一个相对执行时间,然后在StoryboardChain中引入总体时间控制;

l  StoryboardChain中动画的执行顺序就是其中Storyboard声明的顺序,可以仿照Panel中的方式,设置每个Storyboard的ZIndex,用ZIndex调整动画的执行顺序

l  ……

限于篇幅,这里就不对这些改进进行一一的讨论了。所要说明的是,这些改进相对比较简单。完全可以在现有的框架基础上实现。

WPF博大精深,作者水平有限,在发现Storyboard不擅长表示动画序列后也查阅了一些资料。由于没有找到好的方式,才自己实现了这个类。如果大家有更好的解决方案,还请不吝赐教!

TransTest

by LiWei













本文转自百度技术51CTO博客,原文链接:http://blog.51cto.com/baidutech/1033616,如需转载请自行联系原作者

相关文章
|
2月前
|
C#
WPF中动画教程(DoubleAnimation的基本使用)
WPF中动画教程(DoubleAnimation的基本使用)
58 0
|
19天前
|
算法 C# Windows
不可不知的WPF动画(Animation)
【9月更文挑战第19天】在 WPF(Windows Presentation Foundation)中,动画能为应用程序增添生动性和交互性。主要类型包括线性动画和关键帧动画,可针对依赖属性和自定义属性操作。触发方式有事件触发和自动触发,支持暂停、恢复及停止控制。合理使用这些功能并注意性能优化,可创建引人入胜的用户界面。
|
2月前
|
C# UED 开发者
WPF与性能优化:掌握这些核心技巧,让你的应用从卡顿到丝滑,彻底告别延迟,实现响应速度质的飞跃——从布局到动画全面剖析与实例演示
【8月更文挑战第31天】本文通过对比优化前后的方法,详细探讨了提升WPF应用响应速度的策略。文章首先分析了常见的性能瓶颈,如复杂的XAML布局、耗时的事件处理、不当的数据绑定及繁重的动画效果。接着,通过具体示例展示了如何简化XAML结构、使用后台线程处理事件、调整数据绑定设置以及利用DirectX优化动画,从而有效提升应用性能。通过这些优化措施,WPF应用将更加流畅,用户体验也将得到显著改善。
80 0
|
2月前
|
测试技术 C# 开发者
“代码守护者:详解WPF开发中的单元测试策略与实践——从选择测试框架到编写模拟对象,全方位保障你的应用程序质量”
【8月更文挑战第31天】单元测试是确保软件质量的关键实践,尤其在复杂的WPF应用中更为重要。通过为每个小模块编写独立测试用例,可以验证代码的功能正确性并在早期发现错误。本文将介绍如何在WPF项目中引入单元测试,并通过具体示例演示其实施过程。首先选择合适的测试框架如NUnit或xUnit.net,并利用Moq模拟框架隔离外部依赖。接着,通过一个简单的WPF应用程序示例,展示如何模拟`IUserRepository`接口并验证`MainViewModel`加载用户数据的正确性。这有助于确保代码质量和未来的重构与扩展。
35 0
|
2月前
|
C# UED 开发者
WPF动画大揭秘:掌握动画技巧,让你的界面动起来,告别枯燥与乏味!
【8月更文挑战第31天】在WPF应用开发中,动画能显著提升用户体验,使其更加生动有趣。本文将介绍WPF动画的基础知识和实现方法,包括平移、缩放、旋转等常见类型,并通过示例代码展示如何使用`DoubleAnimation`创建平移动画。此外,还将介绍动画触发器的使用,帮助开发者更好地控制动画效果,提升应用的吸引力。
71 0
|
2月前
|
C# Windows 开发者
超越选择焦虑:深入解析WinForms、WPF与UWP——谁才是打造顶级.NET桌面应用的终极利器?从开发效率到视觉享受,全面解读三大框架优劣,助你精准匹配项目需求,构建完美桌面应用生态系统
【8月更文挑战第31天】.NET框架为开发者提供了多种桌面应用开发选项,包括WinForms、WPF和UWP。WinForms简单易用,适合快速开发基本应用;WPF提供强大的UI设计工具和丰富的视觉体验,支持XAML,易于实现复杂布局;UWP专为Windows 10设计,支持多设备,充分利用现代硬件特性。本文通过示例代码详细介绍这三种框架的特点,帮助读者根据项目需求做出明智选择。以下是各框架的简单示例代码,便于理解其基本用法。
77 0
|
2月前
|
存储 C# 数据格式
WPF动画教程(PointAnimationUsingPath的使用)
WPF动画教程(PointAnimationUsingPath的使用)
28 0
|
2月前
|
开发框架 JSON 前端开发
WPF应用框架中工作流模块的介绍
WPF应用框架中工作流模块的介绍
|
5月前
|
C#
WPF —— 动画缩放变换
`ScaleTransform`用于二维x-y坐标系中对象的缩放,可沿X或Y轴调整。在故事板中,通过RenderTransform.ScaleX和ScaleY属性控制缩放。示例代码展示了如何设置按钮的RenderTransformOrigin、Background等属性,并通过LayoutTransform应用ScaleTransform。当鼠标进入按钮时,EventTrigger启动DoubleAnimation实现X和Y轴的缩放动画。最后,展示了如何将动画集成到自定义按钮样式中。
128 0
|
设计模式 编解码 前端开发
WPF技术之UI框架介绍
WPF(Windows Presentation Foundation)是微软公司开发的一种用于创建Windows应用程序的UI框架。它是.NET框架的一部分,是Windows Vista及更高版本操作系统的默认UI框架。
2374 0
WPF技术之UI框架介绍