2009-10-02 41 views
6

Tôi đang tìm hiểu về hoạt ảnh WPF và bối rối về cách áp dụng tuần tự hình động. Như một ví dụ đơn giản, tôi đã có bốn hình chữ nhật trong một lưới thống nhất, và muốn thay đổi màu sắc của mỗi một tuần tự. Dưới đây là những gì tôi có cho đến thời điểm này:WPF - hoạt ảnh tuần tự ví dụ đơn giản

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(); 

    } 

Cách dễ nhất để hoàn thành việc này là gì? Mã trong các ý kiến ​​là dự đoán đầu tiên của tôi, nhưng nó không hoạt động chính xác.

Trả lời

8

Nên có sự kiện ani.Completed - xử lý sự kiện đó và bắt đầu giai đoạn tiếp theo của hoạt ảnh, sau đó bắt đầu hoạt động đầu tiên và mỗi giai đoạn sẽ kích hoạt bước tiếp theo.

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); 
     }; 
    } 
} 

Hãy thử dán trên vào chương trình của bạn. Nó làm những gì bạn cần, nhưng theo cách có thể hữu ích cho bạn trong các ngữ cảnh khác. Nó vẫn là sự kiện điều khiển, nhưng nó sử dụng một "phương pháp lặp" (với lợi tức lợi nhuận) để tạo ấn tượng rằng nó là mã hóa tuần tự mà khối trong khi hoạt hình đang diễn ra.

Điều thú vị về điều này là bạn có thể chơi với phương pháp AnimationSequence theo cách rất trực quan - bạn có thể viết dòng thời gian của hoạt ảnh trong một loạt câu lệnh hoặc sử dụng vòng lặp hoặc bất kỳ thứ gì bạn muốn.

+0

Điều gì xảy ra nếu hoạt ảnh động? Tôi muốn có thể gọi là màu xanh, xanh, đỏ, xanh dương, xanh lục, đỏ; mỗi hoạt ảnh có thể 2 giây sau đó. Có cách nào để làm cho người gọi của animateCell khối cho đến khi ani.Completed được bắn? –

3

Giải pháp mà tôi đã thử là sử dụng Hàng đợi như vậy. Điều này sẽ cho phép bạn thêm vào chuỗi hoạt ảnh động. Tôi không chắc chắn nếu khóa là cần thiết, nhưng tôi để nó ở chỉ để được an toàn.

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

Dễ đọc hơn và hàng đợi khớp với trí tưởng tượng của một chuỗi. Đã triển khai hàng đợi các hành động trong đó một hành động chỉ bắt đầu hoạt ảnh. –

3

này có thể được thực hiện bằng cách sử dụng một lớp học với tên mâu thuẫn ParallelTimeline và cẩn thận điều chỉnh BeginTime tài sản. Lưu ý trong ví dụ bên dưới cách thuộc tính BeginTime của số thứ hai DoubleAnimation được đặt thành thời lượng đầu tiên.

<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> 
Các vấn đề liên quan