2009-10-02 38 views
6

私はWPFアニメーションについて学んでおり、アニメーションを順番に適用する方法については混乱しています。簡単な例として、私は均一なグリッド内に4つの長方形を持っており、それぞれの色を順番に変更したいと考えています。ここに私がこれまで持っているものがあります:WPF - シーケンシャルアニメーション簡単な例

public partial class Window1 : Window 
{ 
    Rectangle blueRect; 
    Rectangle redRect; 
    Rectangle greenRect; 
    Rectangle yellowRect; 

    public Window1() 
    { 
     InitializeComponent(); 
     blueRect = new Rectangle() { Fill = System.Windows.Media.Brushes.Blue, Name="Blue"}; 
     redRect = new Rectangle() { Fill = System.Windows.Media.Brushes.Red, Name="Yellow"}; 
     greenRect = new Rectangle() { Fill = System.Windows.Media.Brushes.Green, Name="Green" }; 
     yellowRect = new Rectangle() { Fill = System.Windows.Media.Brushes.Yellow, Name="Yellow" }; 

     UniformGrid1.Children.Add(blueRect); 
     UniformGrid1.Children.Add(redRect); 
     UniformGrid1.Children.Add(greenRect); 
     UniformGrid1.Children.Add(yellowRect); 

    } 

    private void Window_Loaded(object sender, RoutedEventArgs e) 
    { 
     animateCell(blueRect, Colors.Blue); 
     animateCell(redRect, Colors.Red); 
    } 

    private void animateCell(Rectangle rectangle, Color fromColor) 
    { 
     Color toColor = Colors.White; 
     ColorAnimation ani = new ColorAnimation(toColor, new Duration(TimeSpan.FromMilliseconds(300))); 
     ani.AutoReverse = true; 

     SolidColorBrush newBrush = new SolidColorBrush(fromColor); 
     ani.BeginTime = TimeSpan.FromSeconds(2); 
     rectangle.Fill = newBrush; 
     newBrush.BeginAnimation(SolidColorBrush.ColorProperty, ani); 
     //NameScope.GetNameScope(this).RegisterName(rectangle.Name, rectangle); 
     //Storyboard board = new Storyboard(); 
     //board.Children.Add(ani); 
     //Storyboard.SetTargetName(rectangle, rectangle.Name); 
     //Storyboard.SetTargetProperty(ani, new PropertyPath(SolidColorBrush.ColorProperty)); 
     //board.Begin(); 

    } 

これを達成する最も簡単な方法は何ですか?コメントのコードは私の最初の推測ですが、正しく動作していません。

答えて

8

イベントがあるはずです。ani.Completed - そのイベントを処理し、アニメーションの次のフェーズを開始し、最初のイベントを開始して、各フェーズが次のイベントをトリガーします。

ColorAnimation ani = // whatever... 

ani.Completed += (s, e) => 
    { 
     ColorAnimation ani2 = // another one... 

     // and so on 
    }; 

newBrush.BeginAnimation(SolidColorBrush.ColorProperty, ani); 

UPDATE:

public partial class Window1 : Window 
{ 
    Rectangle blueRect; 
    Rectangle redRect; 
    Rectangle greenRect; 
    Rectangle yellowRect; 

    public Window1() 
    { 
     InitializeComponent(); 
     blueRect = new Rectangle() { Fill = System.Windows.Media.Brushes.Blue, Name = "Blue" }; 
     redRect = new Rectangle() { Fill = System.Windows.Media.Brushes.Red, Name = "Yellow" }; 
     greenRect = new Rectangle() { Fill = System.Windows.Media.Brushes.Green, Name = "Green" }; 
     yellowRect = new Rectangle() { Fill = System.Windows.Media.Brushes.Yellow, Name = "Yellow" }; 

     UniformGrid1.Children.Add(blueRect); 
     UniformGrid1.Children.Add(redRect); 
     UniformGrid1.Children.Add(greenRect); 
     UniformGrid1.Children.Add(yellowRect); 
    } 

    IEnumerable<Action<Action>> AnimationSequence() 
    { 
     for (; ;) 
     { 
      yield return AnimateCell(blueRect, Colors.Blue); 
      yield return AnimateCell(redRect, Colors.Red); 
      yield return AnimateCell(greenRect, Colors.Green); 
      yield return AnimateCell(yellowRect, Colors.Yellow); 
     } 
    } 

    private IEnumerator<Action<Action>> _actions; 

    private void RunNextAction() 
    { 
     if (_actions.MoveNext()) 
      _actions.Current(RunNextAction); 
    } 

    private void Window_Loaded(object sender, RoutedEventArgs e) 
    { 
     _actions = AnimationSequence().GetEnumerator(); 
     RunNextAction(); 
    } 

    private Action<Action> AnimateCell(Rectangle rectangle, Color fromColor) 
    { 
     return completed => 
     { 
      Color toColor = Colors.White; 
      ColorAnimation ani = new ColorAnimation(toColor, 
            new Duration(TimeSpan.FromMilliseconds(300))); 
      ani.AutoReverse = true; 
      ani.Completed += (s, e) => completed(); 

      SolidColorBrush newBrush = new SolidColorBrush(fromColor); 
      ani.BeginTime = TimeSpan.FromSeconds(2); 
      rectangle.Fill = newBrush; 
      newBrush.BeginAnimation(SolidColorBrush.ColorProperty, ani); 
     }; 
    } 
} 

あなたのプログラムに上記貼り付けてください。それはあなたが必要とするものを行いますが、他の状況ではあなたにとって有用な方法で行います。それでもイベント駆動型ですが、アニメーションが進行している間にブロックされるシーケンシャルなコーディングであるという印象を作り出すためには、「イテレータメソッド」(yield return)を使用します。

AnimationSequenceメソッドは非常に直感的な方法で遊ぶことができます。アニメーションのタイムラインを一連のステートメントで書き出したり、ループなどを使用したりできます。

+0

アニメーションが動的な場合はどうなりますか?私は、青、緑、赤、青、緑、赤と言うことができるようにしたいと思います。各アニメーションは前の2秒後かもしれません。 ani.Completedが呼び出されるまでanimateCellの呼び出し元をブロックする方法はありますか? –

3

私が試みた解決策は、キューをそう使用することです。これにより、アニメーションチェーンに動的に追加することができます。ロックが必要かどうかは分かりませんが、安全のためだけにロックを残しました。

Queue<Object[]> animationQueue = new Queue<Object[]>(); 

void sequentialAnimation(DoubleAnimation da, Animatable a, DependencyProperty dp) 
{ 
    da.Completed += new EventHandler(da_Completed); 

    lock (animationQueue) 
    { 
     if (animationQueue.Count == 0) // no animation pending 
     { 
      animationQueue.Enqueue(new Object[] { da, a, dp }); 
      a.BeginAnimation(dp, da); 
     } 
     else 
     { 
      animationQueue.Enqueue(new Object[] { da, a, dp }); 
     } 
    } 
} 

void da_Completed(object sender, EventArgs e) 
{ 
    lock (animationQueue) 
    { 
     Object[] completed = animationQueue.Dequeue(); 
     if (animationQueue.Count > 0) 
     { 
      Object[] next = animationQueue.Peek(); 
      DoubleAnimation da = (DoubleAnimation)next[0]; 
      Animatable a = (Animatable)next[1]; 
      DependencyProperty dp = (DependencyProperty)next[2]; 

      a.BeginAnimation(dp, da); 
     } 
    } 
} 
+0

より多くの読み込みが可能で、キューはシーケンスの想像力にマッチします。アクションがアニメーションを開始するアクションのキューを実装しました。 –

3

これは矛盾した名前ParallelTimelineでクラスを使用して、慎重にBeginTimeプロパティを調整することによって達成することができます。以下の例では、DoubleAnimationBeginTimeプロパティが最初の期間に設定されていることに注意してください。

<ParallelTimeline> 
     <DoubleAnimation 
      Storyboard.TargetName="FlashRectangle" 
      Storyboard.TargetProperty="Opacity" 
      From="0.0" To="1.0" Duration="0:0:1"/> 
     <DoubleAnimation BeginTime="0:0:0.05" 
      Storyboard.TargetName="FlashRectangle" 
      Storyboard.TargetProperty="Opacity" 
      From="1.0" To="0.0" Duration="0:0:2"/> 
</ParallelTimeline>