WPF,动画的IsAdditive属性和属性值的优先级第一段代码:DoubleAnimation widthAnimation new DoubleAnima
WPF,动画的IsAdditive属性和属性值的优先级 第一段代码:
DoubleAnimation widthAnimation = new DoubleAnimation(); widthAnimation.From = 75; widthAnimation.To = 130; widthAnimation.Duration = TimeSpan.FromSeconds(0.5); button1.BeginAnimation(Button.WidthProperty, widthAnimation); button1.Width = 300;这段代码当动画执行完之后,Width属性值为130,最后一句不会起作用,因为动画的属性值的优先级高
第二段代码:
DoubleAnimation widthAnimation = new DoubleAnimation(); widthAnimation.From = 75; widthAnimation.To = 130; widthAnimation.Duration = TimeSpan.FromSeconds(0.5); widthAnimation.IsAdditive = true; button1.BeginAnimation(Button.WidthProperty, widthAnimation); button1.Width = 300;第二段代码,设置了IsAdditive 属性为true,为什么最后设置Width的代码起作用了呢?IsAdditive属性能改变优先级吗?
[解决办法] 我验证了一下,这确实是一个很奇怪的问题。
至于第二段代码,button的宽度只有在大于动画后的button的长度的时候,而且是第一次才起作用。
即,假如button1.width=50;那么是看不到效果的。
即使改成button1.Width+=300;也只有在第一次动画执行后才有效果。第二,三次就没有效果了。
我觉得第二段代码的情况不正常,难道是bug?
[解决办法] 第一个问题,是由于“动画”没有停止,详情请看:
http://msdn.microsoft.com/en-us/library/aa970493%28v=vs.100%29.aspx
里面提到的其中一个停止动画的办法是:
button1.BeginAnimation(Button.WidthProperty, null); //这样Width就会有变化了 button1.Width = 300;[解决办法] 对于第二个问题,DoubleAnimation.IsAdditive属性的解释是:
获取或设置一个值,该值指示是否应将目标属性的当前值与此动画的起始值相加。
[解决办法] 引用: 对于第二个问题,DoubleAnimation.IsAdditive属性的解释是: 获取或设置一个值,该值指示是否应将目标属性的当前值与此动画的起始值相加。 晕死,没打完就按错回复了。。。接着说。。。
==================================================================
我的理解是,既然设置为true,即动画值与目标属性值就需要“互动”,动画值自然不能覆盖目标属性值(overriding the base value),这里的理解是根据2楼那msdn的内容写的
[解决办法]
DoubleAnimation widthAnimation = new DoubleAnimation();
widthAnimation.From = 150;
widthAnimation.Duration = TimeSpan.FromSeconds(0.5);
button1.BeginAnimation(Button.WidthProperty, widthAnimation);
button1.Width = 300;
这个最后的设置也是起了作用的,作何解释
请仔细看 DoubleAnimation.IsAdditive属性(!!!):
http://msdn.microsoft.com/zh-cn/library/vstudio/system.windows.media.animation.doubleanimation.isadditive.aspx
[解决办法] 我6楼的回复应该错了。那里的“无效”好像不能直接当成是“false”。 我的理解是,只有“From”或“To”或“By”属性,这个动画是不是“不完整”的,既然不完整,那是不是动画的值就没有“锁住”目标的值呢?[解决办法] 有这时间去看下源码就知道了。。。 protected override double GetCurrentValueCore(double defaultOriginValue, double defaultDestinationValue, AnimationClock animationClock) { if (!this._isAnimationFunctionValid) { this.ValidateAnimationFunction(); } double normalizedTime = animationClock.CurrentProgress.Value; IEasingFunction easingFunction = this.EasingFunction; if (easingFunction != null) { normalizedTime = easingFunction.Ease(normalizedTime); } double num2 = 0.0; double num = 0.0; double num6 = 0.0; double num3 = 0.0; bool flag = false; bool flag2 = false; switch (this._animationType) { case AnimationType.Automatic: num2 = defaultOriginValue; num = defaultDestinationValue; flag = true; flag2 = true; break; case AnimationType.From: num2 = this._keyValues[0]; num = defaultDestinationValue; flag2 = true; break; case AnimationType.To: num2 = defaultOriginValue; num = this._keyValues[0]; flag = true; break; case AnimationType.By:
num = this._keyValues[0]; num3 = defaultOriginValue; flag = true; break; case AnimationType.FromTo: num2 = this._keyValues[0]; num = this._keyValues[1]; if (this.IsAdditive) { num3 = defaultOriginValue; flag = true; } break; case AnimationType.FromBy: num2 = this._keyValues[0]; num = AnimatedTypeHelpers.AddDouble(this._keyValues[0], this._keyValues[1]); if (this.IsAdditive) { num3 = defaultOriginValue; flag = true; } break; } if (flag && !AnimatedTypeHelpers.IsValidAnimationValueDouble(defaultOriginValue))
{ throw new InvalidOperationException(SR.Get("Animation_Invalid_DefaultValue", new object[] { base.GetType(), "origin", defaultOriginValue.ToString(CultureInfo.InvariantCulture) })); } if (flag2 && !AnimatedTypeHelpers.IsValidAnimationValueDouble(defaultDestinationValue)) { throw new InvalidOperationException(SR.Get("Animation_Invalid_DefaultValue", new object[] { base.GetType(), "destination", defaultDestinationValue.ToString(CultureInfo.InvariantCulture) })); } if (this.IsCumulative) { int? nullable2 = animationClock.CurrentIteration - 1; double factor = (double) nullable2.Value; if (factor > 0.0) { num6 = AnimatedTypeHelpers.ScaleDouble(AnimatedTypeHelpers.SubtractDouble(num, num2), factor); } } return AnimatedTypeHelpers.AddDouble(num3, AnimatedTypeHelpers.AddDouble(num6, AnimatedTypeHelpers.InterpolateDouble(num2, num, normalizedTime))); }
[解决办法] 只有在AnimationType.FromTo 或者AnimationType.FromBy的时候,IsAdditive才会做判断[解决办法] 楼主在问第二段代码的问题,第一段代码没什么异议。 KumaPower, 你给出的是MSDN的IsAdditive的使用规则,但并不能解释第二段代码的疑问。楼主的使用方法没错。 ariesget,你从源代码层面解释的IsAdditive的使用规则,即如果动画仅设置了其 From、To 或 By 属性之一,则设置此属性将无效。跟楼主第二段代码中的问题也没有什么关系。楼主使用的规则也是正确的,没什么问题。[解决办法] 没仔细看问题,第2个的话,因为你IsAdditive为True的时候,你的宽度是从你设置的Button的宽度+上From的值到+上To的值。表现就是300+75到300+130的动画。默认的FillBehavior是HoldEnd,也就是说,动画结束后会保持300+130的宽度。你可以把FillBehavior设置为Stop看下,动画结束后就会回到设置的值。 [解决办法]
[解决办法] 引用: 没仔细看问题,第2个的话,因为你IsAdditive为True的时候,你的宽度是从你设置的Button的宽度+上From的值到+上To的值。表现就是300+75到300+130的动画。默认的FillBehavior是HoldEnd,也就是说,动画结束后会保持300+130的宽度。你可以把FillBehavior设置为Stop看下,动画结束后就会回到设置的值。 FillBehavior 设置成stop当然可以了。你说都是正常的情况。 试想一下,就像你说的。刚开始的时候,button.width 是50,而且默认FillBehavior是HoldEnd。这时,宽度会从50 +75变化到50+130,也就是最后width是180,而且再强调一下,这时FillBehavior仍然是HoldEnd。所以你现在再做button1.Width = 300;本应该UI上的Button的Width是不会改变的。但事实是改变了。这就是问题所在。 14楼,你也看一下。先搞明白问题在哪里。[解决办法] 引用: Quote: 引用: 没仔细看问题,第2个的话,因为你IsAdditive为True的时候,你的宽度是从你设置的Button的宽度+上From的值到+上To的值。表现就是300+75到300+130的动画。默认的FillBehavior是HoldEnd,也就是说,动画结束后会保持300+130的宽度。你可以把FillBehavior设置为Stop看下,动画结束后就会回到设置的值。 FillBehavior 设置成stop当然可以了。你说都是正常的情况。 试想一下,就像你说的。刚开始的时候,button.width 是50,而且默认FillBehavior是HoldEnd。这时,宽度会从50 +75变化到50+130,也就是最后width是180,而且再强调一下,这时FillBehavior仍然是HoldEnd。所以你现在再做button1.Width = 300;本应该UI上的Button的Width是不会改变的。但事实是改变了。这就是问题所在。 14楼,你也看一下。先搞明白问题在哪里。 为什么要不变呢? 所谓HoldEnd跟Stop,只是把原始的值做了一个备份。当Stop的时候就把Width设置回原始值,HoldEnd的时候就用不做这步。这时候你再设置Button1的值跟动画没关系啊。只是正常的设置而已。[解决办法] 引用: Quote: 引用: Quote: 引用: 没仔细看问题,第2个的话,因为你IsAdditive为True的时候,你的宽度是从你设置的Button的宽度+上From的值到+上To的值。表现就是300+75到300+130的动画。默认的FillBehavior是HoldEnd,也就是说,动画结束后会保持300+130的宽度。你可以把FillBehavior设置为Stop看下,动画结束后就会回到设置的值。 FillBehavior 设置成stop当然可以了。你说都是正常的情况。 试想一下,就像你说的。刚开始的时候,button.width 是50,而且默认FillBehavior是HoldEnd。这时,宽度会从50 +75变化到50+130,也就是最后width是180,而且再强调一下,这时FillBehavior仍然是HoldEnd。所以你现在再做button1.Width = 300;本应该UI上的Button的Width是不会改变的。但事实是改变了。这就是问题所在。 14楼,你也看一下。先搞明白问题在哪里。 为什么要不变呢? 所谓HoldEnd跟Stop,只是把原始的值做了一个备份。当Stop的时候就把Width设置回原始值,HoldEnd的时候就用不做这步。这时候你再设置Button1的值跟动画没关系啊。只是正常的设置而已。 测试了下,确实有点不正常,现象跟你前面说的一样。------解决方案--------------------
请问按照楼主第二部分的代码: 请问按照楼主第二部分的代码: DoubleAnimation widthAnimation = new DoubleAnimation(); widthAnimation.From = 75; widthAnimation.To = 130; widthAnimation.Duration = TimeSpan.FromSeconds(0.5); widthAnimation.IsAdditive = true; button1.BeginAnimation(Button.WidthProperty, widthAnimation); button1.Width = 300; 正常的现象应该是什么? 从楼主的发帖就能看出来,正常的话: button1.Width = 300; 这个设置不应该在UI上体现出来。[解决办法] 回家做了点测试。由于没找到这部分执行的源码,只能靠测试结果猜测下。。。首先是当IsAdditive设置为true的时候,第一次执行完动画,width变为width + to的值,此时改变width属性,width变为改变后的width + to的值。然后第2次执行后,再改变width的值,没有效果,也就是被holdend的效果了。那么可以猜测,holdend他保存的是动画的参数to的值,而设置了IsAdditive后他在目标属性上的体现会是一个原始值 + to的值。第一次执行的时候,改原始值就是设置的width属性,所以此时修改width属性,会通知到视觉树上改变属性值,而之后对该属性值的其他设置为IsAdditive的动画,则跟width属性没有关系,width属性被存为一个备份,之后该属性值的设置为IsAdditive的动画都已前一个动画结束后的值为原始值,每次结束后依旧是原始值 + to的值。所以从第2个对该属性的动画开始,设置该属性不会影响到最后holdend的值了,只是修改了备份值。[解决办法] 引用: 所谓HoldEnd跟Stop,只是把原始的值做了一个备份。当Stop的时候就把Width设置回原始值,HoldEnd的时候就用不做这步。这时候你再设置Button1的值跟动画没关系啊。只是正常的设置而已。 动画并不改变Width值。 反过来说,你以为控件的当前显示宽度是Width决定的?这是错误的。Width只是表示你设置的一个模型(理想)值,当前控件真正的宽度并不是Width决定的。 动画过程中根本不设置Width值,控件的可见宽度根本不必等于Width。除非当Stop以后。[解决办法]
引用: Quote: 引用: 所谓HoldEnd跟Stop,只是把原始的值做了一个备份。当Stop的时候就把Width设置回原始值,HoldEnd的时候就用不做这步。这时候你再设置Button1的值跟动画没关系啊。只是正常的设置而已。 动画并不改变Width值。 反过来说,你以为控件的当前显示宽度是Width决定的?这是错误的。Width只是表示你设置的一个模型(理想)值,当前控件真正的宽度并不是Width决定的。 动画过程中根本不设置Width值,控件的可见宽度根本不必等于Width。除非当Stop以后。 恩。动画过程中应该是这样吧。不过这个过程中跟这个问题关系不大貌似。主要是动画结束后,HoldEnd的情况下,如果是IsAdditive=true并且是第一次执行完动画后,修改Width的值会直接影响UI上显示的宽度为修改后的Width+To的值,然后之后运行后再修改都不会影响。所以我有#20的猜测。反编译查源码实在是找不到这块的实现,太大了...[解决办法] 引用: 从楼主的发帖就能看出来,正常的话: button1.Width = 300; 这个设置不应该在UI上体现出来。 怎么我反而觉得这个设置是应该在UI上呈现呢。。。 我换个写法写楼主的代码: DoubleAnimation widthAnimation = new DoubleAnimation(); public MainWindow() { InitializeComponent(); widthAnimation.Completed += new EventHandler(widthAnimation_Completed); widthAnimation.From = 75; widthAnimation.To = 130; widthAnimation.Duration = TimeSpan.FromSeconds(0.5); //条件1 //widthAnimation.IsAdditive = true; widthAnimation.FillBehavior = FillBehavior.HoldEnd; //widthAnimation.FillBehavior = FillBehavior.Stop; } private void button1_Click(object sender, RoutedEventArgs e) { button1.BeginAnimation(Button.WidthProperty, widthAnimation); } void widthAnimation_Completed(object sender, EventArgs e) { //条件2 //button1.BeginAnimation(Button.WidthProperty, null); button1.Width = 300; MessageBox.Show(button1.Width.ToString()); }
条件1:获取或设置一个值,该值指示是否应将目标属性的当前值与此动画的起始值相加。 条件2:移除动画。 情况1(widthAnimation.IsAdditive = false;动画不移除): 结果:130。我的理解:主要原因是动画没有移除,DoubleAnimation仍然重写着Button的Width值。 -----------------------------------------------情况2(widthAnimation.IsAdditive = false;动画移除): 结果:300。我的理解:主要原因是动画移除了,DoubleAnimation没有影响到Width值了,所以当前值会更改成300。 -----------------------------------------------情况3(widthAnimation.IsAdditive = true;动画不移除)[楼主的第二部分]: 结果:430(130+300)。虽然动画没有移除,但IsAdditive设为true,造成DoubleAnimation没有重写Width值,而且能与目标属性“互动”。 ---------------------------------------------- 情况3(widthAnimation.IsAdditive = true;动画移除): 结果:300。原因与情况2相当。 ================================================================================== 我觉得问题的原因是:button1.Width = 300之前,动画是否移除,IsAdditive属性的是否造成DoubleAnimation重写Width值。 FillBehavior.Stop的设置是告诉动画结束不再影响Width值,而FillBehavior.HoldEnd是会影响Width值,但它不是负责重写Width。