题
我学习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();
}
什么是解决这个问题的最简单的方法?在评论的代码是我第一次的猜测,但它不能正常工作。
解决方案
有应的事件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);
};
}
}
尝试上述粘贴到程序中。它做你所需要的,但在某种程度上,可能在其他情况下对你有用。它仍然是事件驱动的,但它使用了一个“迭代方法”(与返回产率)来创建的印象是,它是连续的编码,该编码块,而动画回事。
关于这样做的好处是,你可以玩,在一个非常直观的方式AnimationSequence方法 - 你可以写出来的动画的时间线中的一系列语句,或使用循环,或任何你想。 p>
其他提示
我已经尝试的解决方案是使用一个队列像这样。这将让你加入到动画链动态。我不知道如果锁是必要的,但我离开它只要是安全的。
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);
}
}
}
这可以通过使用一类具有矛盾的名称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>
不隶属于 StackOverflow