完成时动画'抽搐'

时间:2011-10-20 09:46:22

标签: c# silverlight xaml expression-blend easing

我正在使用Microsoft Interactivity和Microsoft Interactions根据代码隐藏中的Property旋转对象。为了使旋转更加平滑,我添加了一个缓动功能。它可以完美地制作动画,但是当它到达动画结束的1个分割帧时,旋转将重置为动画之前的值,然后切换回旋转后的值,导致它来回“抽搐” 。这只发生在EaseOut上。

<i:Interaction.Triggers>
    <ie:PropertyChangedTrigger Binding="{Binding Rotation}">
        <ie:ChangePropertyAction TargetName="RotateTransformer" PropertyName="Angle" Value="{Binding Rotation}" Duration="0:0:2">
            <ie:ChangePropertyAction.Ease>                        
                <BackEase EasingMode="EaseOut" Amplitude="1.2" />
            </ie:ChangePropertyAction.Ease>
        </ie:ChangePropertyAction>
    </ie:PropertyChangedTrigger>
</i:Interaction.Triggers>
<Path Stroke="Black" Fill="Gray">
    <Path.RenderTransform>
        <RotateTransform x:Name="RotateTransformer" CenterX="64" CenterY="105" />
    </Path.RenderTransform>
    <Path.Data>
        <PathGeometry>
            <PathFigureCollection>
                <PathFigure StartPoint="64,0" >
                    <LineSegment Point="39,110" />
                    <LineSegment Point="64, 70" />
                    <LineSegment Point="39,180" />
                    <LineSegment Point="89, 180" />
                    <LineSegment Point="64,70"/>
                    <LineSegment Point="89,110" />
                    <LineSegment Point="64,0" />
                </PathFigure>
            </PathFigureCollection>
        </PathGeometry>
    </Path.Data>
</Path>

2 个答案:

答案 0 :(得分:4)

由于这似乎是ChangePropertyAction类实现中的一个错误,我认为最好的方法是将程序集放入您最喜欢的反射器样式应用程序中,并查看实现的内容

这是一段摘录(有很多遗漏,但相关位在那里):

  public class ChangePropertyAction : TargetedTriggerAction<object>
  {
    /* some dependency properties here, like DurationProperty, ValueProperty, etc... */


    protected override void Invoke(object parameter)
    {
       /* a lot of validation here, but skimming over that mostly. Valid input results in a call to AnimatePropertyChange() */
    }

    private void AnimatePropertyChange(PropertyInfo propertyInfo, object fromValue, object newValue)
    {
      Storyboard storyboard = new Storyboard();
      Timeline timeline = !typeof (double).IsAssignableFrom(propertyInfo.PropertyType) 
                ? (!typeof (Color).IsAssignableFrom(propertyInfo.PropertyType)
                ? (!typeof (Point).IsAssignableFrom(propertyInfo.PropertyType)
                ? this.CreateKeyFrameAnimation(fromValue, newValue)
                    : this.CreatePointAnimation((Point) fromValue, (Point) newValue))
                    : this.CreateColorAnimation((Color) fromValue, (Color) newValue))
                    : this.CreateDoubleAnimation((double) fromValue, (double) newValue);
      timeline.Duration = this.Duration;
      storyboard.Children.Add(timeline);
      Storyboard.SetTarget((Timeline) storyboard, (DependencyObject) this.Target);
      Storyboard.SetTargetProperty((Timeline) storyboard, new PropertyPath(propertyInfo.Name, new object[0]));
      storyboard.Completed += (EventHandler) ((o, e) => propertyInfo.SetValue(this.Target, newValue, new object[0]));
      storyboard.FillBehavior = FillBehavior.Stop;
      storyboard.Begin();
    }

    private static object GetCurrentPropertyValue(object target, PropertyInfo propertyInfo)
    {
      FrameworkElement frameworkElement = target as FrameworkElement;
      target.GetType();
      object obj = propertyInfo.GetValue(target, (object[]) null);
      if (frameworkElement != null && (propertyInfo.Name == "Width" || propertyInfo.Name == "Height") && double.IsNaN((double) obj))
        obj = !(propertyInfo.Name == "Width") ? (object) frameworkElement.ActualHeight : (object) frameworkElement.ActualWidth;
      return obj;
    }

    private Timeline CreateDoubleAnimation(double fromValue, double newValue)
    {
      return (Timeline) new DoubleAnimation()
      {
        From = new double?(fromValue),
        To = new double?(newValue),
        EasingFunction = this.Ease
      };
    }
  }

如果您想查看完整代码,请自行通过DotPeek或ILSpy运行,两者都是免费的: - )

所以最后,它所做的只是验证输入,查看值的类型并创建一个故事板,其中包含适合于属性类型的过渡动画。 “闪烁”效果实际上是在动画完成时短暂返回其原始值(实际上已绑定)的值,之后更新绑定以反映新值。 此行为的原因归结为故事板上的单个属性设置:

storyboard.FillBehavior = FillBehavior.Stop;

此FillBehavior确定时间轴(本例中的故事板)到达结束时会发生什么。 MSDN有这样的说法:

  

HoldEnd :在其有效期结束后,时间线   保持其进展直到其父母的活跃并持有   周期。

     

停止:如果时间线超出其有效期限,则时间线会停止   父母在其活跃期间。

如果我们只是将此属性更改为设置为FillBehavior.HoldEnd,则闪烁消失。缺点是你必须重新实现这个TriggerAction,但如果你只是想让它适用于双动画,你可能会遗漏很多。

希望这对任何人都有帮助!

答案 1 :(得分:2)

我注意到的一件事,CenterXCenterY应该是小数且小于1,例如CenterY="0.45" CenterX="0.4" 错误!

<强>更新

花了一些时间玩ChangePropertyAction之后,无论你选择哪种缓和功能,我都发现动画总会闪烁。

我认为这是一个错误......