You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 04:36:03