一般,为用户界面应用动画只不过是建立并配置正确的动画和故事板对象。但在其余状况下,特别是同时发生多个动画时,可能须要更加关注性能。特定的效果更可能致使这些问题——例如,那些涉及视频、大位图以及多层透明等的效果一般须要占用更多CPU开销。若是不谨慎实现这类效果,运行它们使可能形成明显抖动,或者会从其余同时运行的应用程序抢占CPU时间。缓存
幸运的是,WPF提供了几个可提供帮助的技巧。接下来的几节将学习下降最大帧率以及缓存计算机显卡中的位图,这两种技术能够减轻CPU的负担。安全
1、指望的帧率布局
正如前面所学习的,WPF试图保持以60帧/秒的速度运动动画。这样可确保从开始到结束获得平滑流畅的动画。固然,WPF可能达不到这个目标。若是同时运行多个复杂的动画,而且CPU或显卡不能承受的话,整个帧率可能会降低(最好的情形),甚至可能会跳跃以进行补偿(最坏的情形)。性能
尽管不多提升帧率,但可能会选择下降帧率,这多是由于如下两个缘由之一:学习
调整帧率很容易。只须要为包含动画的故事板使用Timeline.DesiredFrameRate附加属性。下面的示例将帧率减半:测试
<Storyboard Timeline.DesiredFrameRate="30">
下图显示了一个简单的测试程序,该程序为一个小球应用动画,使其在Canvas控件上沿一条曲线运动。动画
这个应用程序开始在Canvas上绘制Ellipse对象。Canvas.ClipToBounds属性被设置为true,因此圆的边缘不会超出Canvas控件的边缘而进入窗口的其余部分。spa
<Canvas ClipToBounds="True"> <Ellipse Name="ellipse" Fill="Red" Width="10" Height="10"></Ellipse> </Canvas>
为在Canvas控件上移动圆,须要同时进行两个动画——一个动画用于更新Canva.Left属性(从左向右移动圆),另外一个动画用于改变Canvas.Top属性(使圆上升,而后降低)。Canvas.Top动画是可反转的——一旦圆达到最高点,就会降低。Canvas.Left动画不是可反转的,但持续时间是Canvas.Top动画的两倍,从而使得这两个动画能够同时移动圆。最后的技巧是为Canvas.Top动画使用DeceleartionRatio属性。这样,当圆达到最高点是上升的速度会更慢,这会建立更逼真的效果。code
下面是动画的完整标记:orm
<Window.Resources> <BeginStoryboard x:Key="beginStoryboard"> <Storyboard Timeline.DesiredFrameRate="{Binding ElementName=txtFrameRate,Path=Text}"> <DoubleAnimation Storyboard.TargetName="ellipse" Storyboard.TargetProperty="(Canvas.Left)" From="0" To="300" Duration="0:0:5"> </DoubleAnimation> <DoubleAnimation Storyboard.TargetName="ellipse" Storyboard.TargetProperty="(Canvas.Top)" From="300" To="0" AutoReverse="True" Duration="0:0:2.5" DecelerationRatio="1"> </DoubleAnimation> </Storyboard> </BeginStoryboard> </Window.Resources>
这个示例的真正目的是尝试不一样的帧率。为查看某个特定帧率的效果,只须要在文本框中输入合适的数值,而后单击Repeat按钮便可。而后动画就会使用新的帧率(经过数据绑定表达式获取新的帧率)触发,从而能够观察动画的效果。在更低的帧率下,椭圆不会均匀移动——而会在Cavans控件中的跳跃。
也可以使用代码调整Timeline.DesiredFrame属性。例如,可能但愿读取静态属性RenderCapability.Tier以肯定显卡支持的渲染级别。
2、位图缓存
位图缓存通知WPF获取内容的当前位图图像,并将其复制到显卡的内存中。这时,显卡能够控制位图的操做和显示的刷新。这个处理过程比让WPF完成全部工做要快不少,而且和显卡不断通讯。
若是运用得当,位图缓存能够改善应用程序的绘图性能。但若是运用不当,就会浪费显存而且实际上会下降性能。因此,在使用位图缓存以前,须要确保真正合适。下面列出一些指导原则:
为更好地理解位图缓存,使用一个简单示例是有帮助的,下图例举一个示例,一个动画推进一个简单的图像——正方形——在Canvas面板上移动,Canvas面板包含一条具备复杂集合图形的路径。但正方形在Canvas面板表面上移动时,强制WPF从新计算路径并填充丢失的部分。这会带来极大的CPU负担,而且动画甚至可能开始变得断断续续。
可采用几种方法解决该问题。一种选择是使用一幅位图替换背景,WPF可以更高效地管理位图。更灵活的选择是使用位图缓存,这种方法可继续将存活的、可交互的元素做为背景。
为启用位图缓存功能,将相应元素的CacheMode属性设置为BitmapCache。每一个元素都提供了CacheMode属性,这意味着能够精确选择为哪一个元素使用这一特征。
<Path CacheMode="BitmapCache" ...></Path>
经过这个简单修改,可当即看到区别。首先,窗口显示的事件要稍长一些。但动画的运行将更平滑,而且CPU的负担将显著下降。可经过Windows任务管理器进行检查——常常能够看到CPU的负担从接近100%减小到20%一下。
一般,当启用位图缓存时,WPF采用元素当前尺寸的快照并将其位图复制到显卡中。若是以后使用ScaleTransform放大元素,这会变成一个问题。在这种状况下,将放大缓存的位图,而不是实际的元素,当放大元素时这会致使模糊放大以及色块。
例如,设想一个修订过的示例。在这个示例中,第二个同步动画扩展Path使其为原始尺寸的10倍,而后缩回原始尺寸。为确保具备良好的显示质量,可以使用5倍于Path原始尺寸的尺寸缓存其位图:
<Path ...> <Path.CacheMode> <BitmapCache RenderAtScale="5"></BitmapCache> </Path.CacheMode> </Path>
这样可解决像素化问题。虽然缓存的位图仍比Path的最大动画尺寸(最大尺寸达10倍于其原始尺寸)小,但显卡能使位图的尺寸加倍,从5倍到10倍,而不会有任何明显的缩放问题。更重要的是,这可以使应用避免过多地使用显存。