第一段代码: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属性能改变优先级吗?

解决方案 »

  1.   

    我验证了一下,这确实是一个很奇怪的问题。
    至于第二段代码,button的宽度只有在大于动画后的button的长度的时候,而且是第一次才起作用。
    即,假如button1.width=50;那么是看不到效果的。
    即使改成button1.Width+=300;也只有在第一次动画执行后才有效果。第二,三次就没有效果了。我觉得第二段代码的情况不正常,难道是bug?
      

  2.   

    第一个问题,是由于“动画”没有停止,详情请看:
    http://msdn.microsoft.com/en-us/library/aa970493%28v=vs.100%29.aspx
    里面提到的其中一个停止动画的办法是:button1.BeginAnimation(Button.WidthProperty, null);
    //这样Width就会有变化了
    button1.Width = 300;
      

  3.   

    对于第二个问题,DoubleAnimation.IsAdditive属性的解释是:
    获取或设置一个值,该值指示是否应将目标属性的当前值此动画的起始值相加。
      

  4.   


    晕死,没打完就按错回复了接着说==================================================================
    我的理解是,既然设置为true,即动画值与目标属性值就需要“互动”,动画值自然不能覆盖目标属性值(overriding the base value),这里的理解是根据2楼那msdn的内容写的
      

  5.   


    晕死,没打完就按错回复了接着说==================================================================
    我的理解是,既然设置为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;这个最后的设置也是起了作用的,作何解释
      

  6.   


    晕死,没打完就按错回复了接着说==================================================================
    我的理解是,既然设置为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
      

  7.   


    晕死,没打完就按错回复了接着说==================================================================
    我的理解是,既然设置为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请问..并没有设置IsAdditive,只是省略了To,结果最后的设置起作用了,请问,作何解释
      

  8.   

    我6楼的回复应该错了。那里的“无效”好像不能直接当成是“false”。我的理解是,只有“From”或“To”或“By”属性,这个动画是不是“不完整”的,既然不完整,那是不是动画的值就没有“锁住”目标的值呢?
      

  9.   

    有这时间去看下源码就知道了 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)));
        }
      

  10.   

    只有在AnimationType.FromTo 或者AnimationType.FromBy的时候,IsAdditive才会做判断
      

  11.   

    楼主在问第二段代码的问题,第一段代码没什么异议。KumaPower, 你给出的是MSDN的IsAdditive的使用规则,但并不能解释第二段代码的疑问。楼主的使用方法没错。ariesget,你从源代码层面解释的IsAdditive的使用规则,即如果动画仅设置了其 From、To 或 By 属性之一,则设置此属性将无效。跟楼主第二段代码中的问题也没有什么关系。楼主使用的规则也是正确的,没什么问题。
      

  12.   

    没仔细看问题,第2个的话,因为你IsAdditive为True的时候,你的宽度是从你设置的Button的宽度+上From的值到+上To的值。表现就是300+75到300+130的动画。默认的FillBehavior是HoldEnd,也就是说,动画结束后会保持300+130的宽度。你可以把FillBehavior设置为Stop看下,动画结束后就会回到设置的值。
      

  13.   


    FillBehavior 设置成stop当然可以了。你说都是正常的情况。
    试想一下,就像你说的。刚开始的时候,button.width 是50,而且默认FillBehavior是HoldEnd。这时,宽度会从50 +75变化到50+130,也就是最后width是180,而且再强调一下,这时FillBehavior仍然是HoldEnd。所以你现在再做button1.Width = 300;本应该UI上的Button的Width是不会改变的。但事实是改变了。这就是问题所在。14楼,你也看一下。先搞明白问题在哪里。
      

  14.   


    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的值跟动画没关系啊。只是正常的设置而已。
      

  15.   


    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的值跟动画没关系啊。只是正常的设置而已。
    测试了下,确实有点不正常,现象跟你前面说的一样。
      

  16.   


    现在有点晕了请问按照楼主第二部分的代码: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;正常的现象应该是什么?
      

  17.   


    现在有点晕了请问按照楼主第二部分的代码: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上体现出来。
      

  18.   

    回家做了点测试。由于没找到这部分执行的源码,只能靠测试结果猜测下首先是当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的值了,只是修改了备份值。
      

  19.   


    动画并不改变Width值。反过来说,你以为控件的当前显示宽度是Width决定的?这是错误的。Width只是表示你设置的一个模型(理想)值,当前控件真正的宽度并不是Width决定的。动画过程中根本不设置Width值,控件的可见宽度根本不必等于Width。除非当Stop以后。
      

  20.   


    动画并不改变Width值。反过来说,你以为控件的当前显示宽度是Width决定的?这是错误的。Width只是表示你设置的一个模型(理想)值,当前控件真正的宽度并不是Width决定的。动画过程中根本不设置Width值,控件的可见宽度根本不必等于Width。除非当Stop以后。
    恩。动画过程中应该是这样吧。不过这个过程中跟这个问题关系不大貌似。主要是动画结束后,HoldEnd的情况下,如果是IsAdditive=true并且是第一次执行完动画后,修改Width的值会直接影响UI上显示的宽度为修改后的Width+To的值,然后之后运行后再修改都不会影响。所以我有#20的猜测。反编译查源码实在是找不到这块的实现,太大了...
      

  21.   


    怎么我反而觉得这个设置是应该在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。