5

Microsoft Interactivity と Microsoft Interactions を使用して、コード ビハインドのプロパティに基づいてオブジェクトを回転させています。回転をよりスムーズにするために、イージング関数を追加しました。アニメーションは完全に問題なく実行されますが、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>
4

2 に答える 2

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 を自分で実行してください。どちらも無料です :-)

したがって、最終的には、入力を検証し、値の型を調べて、プロパティの型に適した遷移アニメーションを含むストーリーボードを作成するだけです。「ちらつき」効果とは、実際には、アニメーションが完了すると一時的に元の値 (実際にバインドされている値) に戻る値であり、その後、新しい値を反映するようにバインディングが更新されます。この動作の理由は、ストーリーボードの 1 つのプロパティ設定にあります。

storyboard.FillBehavior = FillBehavior.Stop;

この FillBehavior は、タイムライン (この場合はストーリーボード) が最後に達したときに何が起こるかを決定します。MSDN は次のように述べています。

HoldEnd : アクティブ期間の終わりに達した後、タイムラインは親のアクティブ期間とホールド期間の終わりまで進行を保持します。

Stop : 親がアクティブ期間内にあり、アクティブ期間外にある場合、タイムラインは停止します。

このプロパティを FillBehavior.HoldEnd に設定するだけで、ちらつきがなくなります。欠点は、この TriggerAction を再実装する必要があることですが、ダブル アニメーションで機能させたい場合は、おそらく多くを省略できます。

これが誰にも役立つことを願っています!

于 2012-08-01T19:41:42.023 に答える
2

私が気づいたことの 1 つは、小数で 1 未満である必要があることです。たとえば、CenterX間違っCenterYCenterY="0.45" CenterX="0.4" ています。

アップデート

でしばらく遊んだ後ChangePropertyAction、どのイージング関数を選択しても、アニメーションには常にちらつきがあることがわかりました。

バグだと思います...

于 2011-10-20T11:36:53.963 に答える