若是您在使用WPF/Silverlight进行相关动画开发中使用了Storyboard,并对关联属性进行了动画修改,那么您是否有注意到这些关联属性经常没法再经过直接赋值的形式去修改,尽管它的值已经被更改,但却始终没法在界面上得以体现。例如,在个人C#开发WPF/Silverlight动画及游戏系列教程(Game Tutorial)教程里大量运用了Storyboard对角色的X,Y坐标关联属性以及角色Direction朝向关联属性进行动画形式修改;若是统一的每次更改均使用Storyboard是不会存在任何问题的,结果是所见即所得。可是若是你们在使用Storyboard更改了朝向Direction这个关联属性后,若想经过鼠标右键点击而后再更改角色朝向朝北:Direction = 0,结果却无任何效果;不少朋友怀疑:是否是鼠标右键事件哪一个位置写错了?结果却并不是如此。在WPF/Silverlight中使用Storyboard修改过关联属性后,这些关联属性将被锁定,外界是没法经过直接赋值的形式对其进行修改的。难道一筹莫展了?其实msdn很早就给咱们提供了3个解决方案,原文地址:
http://msdn.microsoft.com/zh-cn/library/aa970493.aspx
下面是我对它们的解析及拓展:html
方法一:将动画的 FillBehavior 属性设置为 Stop:
storyboard.FillBehavior = FillBehavior.Stop;
经过将FillBehavior设置为Stop,即通知动画在到达其活动期末尾后中止影响其目标关联属性。虽然达到了目的,但必须等待动画结束时才会生效,且更关键的是以前被storyboard修改过的全部关联属性值此时都被还原成了初始值。所以,此方法只适合用于制做相似网页中的导航菜单按钮:当鼠标悬停在菜单上时,菜单图形按钮执行一段华丽的变化动画;当鼠标移开后即变回为初始图片。性能
方法二:移除整个动画板(Storyboard)。此方法必须经过相似
Leader.BeginStoryboard(storyboard, HandoffBehavior.SnapshotAndReplace, true);或
storyboard.Begin(Leader, HandoffBehavior.SnapshotAndReplace, true);
这两种方式启动动画,而后在须要解锁时经过
storyboard.Remove(Leader); storyboard = null; 通知动画板动画中止影响名为Leader对象的目标关联属性,并移除storyboard。须要特别注意的是①必须将动画的IsControllable参数设置为true;②HandoffBehavior最好设置为SnapshotAndReplace,此枚举的做用是:新动画将替换它们所应用到的关联属性上的任何现有动画。
方法三:从单个关联属性移除动画。一样的以精灵角色朝向为例,若是该属性已被Storyboard锁定,那么若是此时须要对其值进行更改,咱们能够经过相似:
Leader.BeginAnimation(QXSpirit.DirectionProperty, null);或
Leader.ApplyAnimationClock(QXSpirit.DirectionProperty, null);
这两种方法来禁止关联到Leader的动画继续影响Leader的DirectionProperty关联属性(此方法对于非动画板动画也一样有效)。接着后面咱们就能够轻松的经过Leader.Direction = 0 为精灵的朝向属性进行赋值并在画面中获得体现。
以上三种解决方案在WPF中灵活的配合storyboard.Children.Clear();使用几乎能够应付任何关于Storyboard锁死关联属性的问题;可是在Silverlight中却每每不尽如人意。毕竟只是WPF的子集,在功能与方法上有着太少的支持。所以,我拓展了如下两种解决方案,更重要的,它们均为WPF/Silverlight通用的且药到病除的终极策略。
方法四:能够经过每次运行新的动画时先暂停以前的动画(注意,是暂停(Pause)而不是中止(Stop)),例如storyboard.Pause(Leader);而后再建立一个新的动画板storyboard = new Storyboard();这样,以前被storyboard修改过的关联属性目标值会被新的storyboard做为起点属性值,从而完美实现关联属性在动画与动画之间的衔接。有些朋友会问那以前的storyboard是否会继续占用内存空间?对于.net的内存回收机制咱们没法控知,根据我多方查阅的资料,若您不放心,不妨在建立新的Storyboard前,经过storyboard= null 将之注销掉,在Silverlight动画中我是这样作的,实践证实此方法确实达到的目的。
方法五:以毒攻毒。既然是Storyboard锁死了咱们须要更改的关联属性,那么咱们一样能够经过Storyboard动画的形式来赋值更改这些关联属性。此方法乃下下策,缺点是毫无性能而言;优势是万能性:适合一切被Storyboard锁死的关联属性的修改,且不管是在WPF仍是Silverlight中。下面一样以精灵的朝向为例,咱们能够经过:
DoubleAnimation doubleAnimation = new DoubleAnimation();
doubleAnimation.To = direction;
doubleAnimation.Duration = new Duration(TimeSpan.FromMilliseconds(10));
Storyboard.SetTarget(doubleAnimation, spirit);
Storyboard.SetTargetProperty(doubleAnimation, new PropertyPath("Direction"));
storyboard.Children.Add(doubleAnimation);
storyboard.Begin();这样的动画形式对QXSpirit.DirectionProperty关联属性进行强行更改。