WinUI 3中TextBlock动画链实现求助:淡隐→改文本→淡显
WinUI 3 实现TextBlock淡隐-改文本-淡显的动画链方案
你的问题核心是UI线程访问错误和动画未按顺序执行:Task默认在后台线程执行,直接操作UI控件必然触发线程错误;且你未等待动画实际完成就执行后续操作,导致逻辑顺序混乱。以下是两种可行的实现方案:
方案一:利用Storyboard的Completed事件(贴合WPF习惯)
WinUI 3的Storyboard提供了Completed事件,可直接用来构建动画链,和WPF的动画结束事件逻辑一致:
// 初始化淡隐动画(Opacity从1→0) var fadeOutStoryboard = new Storyboard(); var fadeOutAnimation = new DoubleAnimation { From = 1, To = 0, Duration = TimeSpan.FromSeconds(0.5) // 自定义动画时长 }; Storyboard.SetTarget(fadeOutAnimation, _TextBlock); Storyboard.SetTargetProperty(fadeOutAnimation, "Opacity"); fadeOutStoryboard.Children.Add(fadeOutAnimation); // 初始化淡显动画(Opacity从0→1) var fadeInStoryboard = new Storyboard(); var fadeInAnimation = new DoubleAnimation { From = 0, To = 1, Duration = TimeSpan.FromSeconds(0.5) }; Storyboard.SetTarget(fadeInAnimation, _TextBlock); Storyboard.SetTargetProperty(fadeInAnimation, "Opacity"); fadeInStoryboard.Children.Add(fadeInAnimation); // 构建动画链 fadeOutStoryboard.Completed += (s, e) => { // 淡隐动画结束后修改文本(自动在UI线程执行) _TextBlock.Inlines.Clear(); _TextBlock.Inlines.Add(GetTextInline(phrase)); // 启动淡显动画 fadeInStoryboard.Begin(); }; // 启动第一个动画 fadeOutStoryboard.Begin();
方案二:异步等待式实现(简洁异步逻辑)
如果偏好异步编程风格,可通过TaskCompletionSource包装Completed事件,实现await动画完成的逻辑:
// 封装等待Storyboard完成的异步方法 private async Task WaitForStoryboardComplete(Storyboard storyboard) { var tcs = new TaskCompletionSource<bool>(); void CompletedHandler(object s, object e) { storyboard.Completed -= CompletedHandler; tcs.TrySetResult(true); } storyboard.Completed += CompletedHandler; storyboard.Begin(); await tcs.Task; } // 核心调用逻辑 private async void UpdateTextWithAnimation(string phrase) { // 1. 执行淡隐动画 var fadeOutAnim = new DoubleAnimation { From = 1, To = 0, Duration = TimeSpan.FromSeconds(0.5) }; var fadeOutSb = new Storyboard(); Storyboard.SetTarget(fadeOutAnim, _TextBlock); Storyboard.SetTargetProperty(fadeOutAnim, "Opacity"); fadeOutSb.Children.Add(fadeOutAnim); await WaitForStoryboardComplete(fadeOutSb); // 2. 修改文本内容 _TextBlock.Inlines.Clear(); _TextBlock.Inlines.Add(GetTextInline(phrase)); // 3. 执行淡显动画 var fadeInAnim = new DoubleAnimation { From = 0, To = 1, Duration = TimeSpan.FromSeconds(0.5) }; var fadeInSb = new Storyboard(); Storyboard.SetTarget(fadeInAnim, _TextBlock); Storyboard.SetTargetProperty(fadeInAnim, "Opacity"); fadeInSb.Children.Add(fadeInAnim); await WaitForStoryboardComplete(fadeInSb); } // 触发更新示例 // UpdateTextWithAnimation(yourTargetPhrase);
关键注意事项
- 所有UI操作(动画启动、控件修改)必须在UI线程执行,上述两种方案均天然保证了这一点。
- 避免用
Task.Run或无上下文的Task执行UI操作,必然触发线程错误。 - 你之前代码中
myAnimation2的关键帧逻辑写反(淡显应是0→1而非1→0),已在示例中纠正。
内容的提问来源于stack exchange,提问作者Георгий Попов
相关产品推荐
相关产品推荐

