WPF如何实现多个TextBlock文本动画按顺序执行,前一个结束后再启动下一个
WPF TextBlock顺序动画实现方案
问题根源
你当前同步连续调用两次TextBlockAnimation的写法存在逻辑漏洞:WPF的Storyboard启动是非阻塞的异步操作,调用storyboard.Begin()后不会等待动画执行完成就会立刻执行后续代码,因此第一次动画刚启动,第二次调用就覆盖了TextBlock的文本内容、启动了新动画,最终只会看到最后一段文本的动画效果。
解决方案
方案1:基于Completed事件的队列实现(兼容所有.NET版本)
通过队列维护待播放的文本序列,在每段动画的完成事件中自动触发下一段动画的播放,无需修改原有动画的核心逻辑:
// 类级别变量:待播放文本队列 private Queue<string> _textQueue = new Queue<string>(); // 类级别变量:标记当前是否有动画在播放 private bool _isAnimating = false; private void Window_Loaded(object sender, RoutedEventArgs e) { // 按顺序把要播放的文本加入队列 _textQueue.Enqueue("Hello Foo"); _textQueue.Enqueue("Bye Foo"); // 启动第一个动画 TryPlayNextAnimation(); } private void TryPlayNextAnimation() { // 没有待播放内容或者正在播放就直接返回 if(_textQueue.Count == 0 || _isAnimating) return; _isAnimating = true; var nextText = _textQueue.Dequeue(); TextBlockAnimation(nextText); } public void TextBlockAnimation(string text) { // 原有逻辑:给TextBlock赋值、初始化Storyboard yourTextBlock.Text = text; // storyboard初始化逻辑... // 注册动画完成事件 storyboard.Completed += (s, e) => { _isAnimating = false; // 动画完成后播放下一个 TryPlayNextAnimation(); }; storyboard.Begin(); }
方案2:基于async/await的异步实现(适合.NET Framework 4.5+ / .NET Core 3.0+)
通过扩展方法把Storyboard封装成可等待的Task,用同步的写法实现异步顺序执行,代码更简洁易读:
// Storyboard异步扩展方法 public static class StoryboardExtensions { public static Task BeginAsync(this Storyboard storyboard) { var tcs = new TaskCompletionSource<bool>(); EventHandler handler = null; handler = (s, e) => { storyboard.Completed -= handler; tcs.SetResult(true); }; storyboard.Completed += handler; storyboard.Begin(); return tcs.Task; } } // 业务代码 private async void Window_Loaded(object sender, RoutedEventArgs e) { await TextBlockAnimationAsync("Hello Foo"); await TextBlockAnimationAsync("Bye Foo"); } public async Task TextBlockAnimationAsync(string text) { yourTextBlock.Text = text; // storyboard初始化逻辑... // 等待动画完成再返回 await storyboard.BeginAsync(); }
注意事项
- 每次调用动画方法前建议重新初始化Storyboard实例,不要复用同一个全局Storyboard,避免出现Completed事件重复注册、动画参数冲突的问题
- 如果需要中途打断当前的动画播放序列,第一种方案直接清空
_textQueue即可,第二种方案可以结合CancellationToken实现取消逻辑
内容的提问来源于stack exchange,提问作者Eduardo Silva
相关产品推荐
相关产品推荐

