WPF - 顺序动画简单示例 [英] WPF - sequential animation simple example

查看:38
本文介绍了WPF - 顺序动画简单示例的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在学习 WPF 动画,但对如何按顺序应用动画感到困惑.作为一个简单的例子,我在一个统一的网格中有四个矩形,并且想要依次改变每个矩形的颜色.这是我到目前为止所拥有的:

I'm learning about WPF animation, and am confused about how to apply animations sequentially. As a simple example, I've got four rectangles in a uniform grid, and would like to change the color of each one sequentially. Here's what I have so far:

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

    }

实现这一目标的最简单方法是什么?评论中的代码是我的第一次猜测,但它无法正常工作.

What's the easiest way of accomplishing this? The code in the comments is my first guess, but it's not working correctly.

推荐答案

应该有一个事件 ani.Completed - 处理该事件并开始动画的下一阶段,然后开始第一个阶段运行,每个阶段都会触发下一个.

There should be an event ani.Completed - handle that event and start the next phase of the animation, then start the first one running and each phase will trigger the next.

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

尝试将上述内容粘贴到您的程序中.它可以满足您的需求,但在其他情况下可能对您有用.它仍然是事件驱动的,但它使用了一种迭代器方法"(带收益返回)来创造一种印象,即在动画进行时它是顺序编码的块.

Try pasting the above into your program. It does what you need, but in a way that may be useful to you in other contexts. It's still event driven, but it uses an "iterator method" (with yield return) to create the impression that it is sequential coding that blocks while the animation is going on.

这样做的好处是您可以以非常直观的方式使用 AnimationSequence 方法 - 您可以在一系列语句中写出动画的时间线,或者使用循环,或者任何您想要的.

The nice thing about this is that you can play around with the AnimationSequence method in a very intuitive way - you could write out the timeline of the animation in a series of statements, or use loops, or whatever you want.

这篇关于WPF - 顺序动画简单示例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆