2009-10-02 17 views
6

मैं डब्ल्यूपीएफ एनीमेशन के बारे में सीख रहा हूं, और अनुक्रमिक रूप से एनीमेशन को कैसे लागू करना है, इस बारे में उलझन में हूं। एक साधारण उदाहरण के रूप में, मुझे एक समान ग्रिड में चार आयताकार मिल गए हैं, और क्रमशः प्रत्येक के रंग को बदलना चाहते हैं। यहां मेरे पास अब तक है:डब्ल्यूपीएफ - अनुक्रमिक एनीमेशन सरल उदाहरण

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

अद्यतन:

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

अपने कार्यक्रम में ऊपर चिपकाकर प्रयास करें। यह वही करता है जो आपको चाहिए, लेकिन इस तरह से अन्य संदर्भों में आपके लिए उपयोगी हो सकता है। यह अभी भी घटना संचालित है, लेकिन यह इंप्रेशन बनाने के लिए "इटरेटर विधि" (उपज रिटर्न के साथ) का उपयोग करता है कि यह अनुक्रमिक कोडिंग है जो एनीमेशन चालू होने पर ब्लॉक करता है।

इस बारे में अच्छी बात यह है कि आप एनीमेशन सबक्वेंस विधि के साथ बहुत ही सहज तरीके से खेल सकते हैं - आप एनीमेशन की समयरेखा को कथन की श्रृंखला में लिख सकते हैं, या लूप का उपयोग कर सकते हैं, या जो कुछ भी आप चाहते हैं।

+0

क्या एनिमेशन गतिशील हैं? मैं नीला, हरा, लाल, नीला, हरा, लाल कहने में सक्षम होना चाहता हूं; प्रत्येक एनीमेशन पिछले के बाद 2 सेकंड हो सकता है। Ani तक एनिमेट सेल ब्लॉक के कॉलर को बनाने का कोई तरीका है। पूर्ण निकाल दिया गया है? –

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 संपत्ति का समायोजन करके पूरा किया जा सकता। नीचे दिए गए उदाहरण में ध्यान दें कि BeginTime दूसरी DoubleAnimation की संपत्ति पहले की अवधि पर सेट की गई है।

<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> 
संबंधित मुद्दे