C# 长耗时任务更新界面无效的解决方法

问题现象

希望在一个长耗时任务开始时,显示一个忙状态,然后在结束时恢复界面.

1
2
3
4
5
6
7
8
9
private void DisplayImagePage()
{
// 显示一个忙状态
textblock1.Visibility = Visibility.Visible;
// 耗时操作
Thread.Sleep(1000);
// 恢复界面
textblock1.Visibility = Visibility.Hidden;
}

现象: 界面卡死,textblock1 从未显示出来,1秒后界面恢复鼠标相应.

原因: 耗时操作让textblock1来不及更新,就进入了 CPU 密集型操作,耗时操作结束后,界面更新,瞬间切换了 textblock1 的可见显示状态,导致屏幕无法刷新出这个控件。

解决方法

把整个对界面更新的过程封装到一个 Task 里面去执行,且使用异步模式执行。在切换显示后,休眠几毫秒,保证界面更新,然后再执行耗时操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
private void DisplayImagePage()
{
Task.Run(async () =>
{
// 把显示文本也封装成异步方法
await ShowBusyStatusAsync();
// 额外休眠一段时间保证界面更新
await Task.Delay(50);
// 耗时操作,这里面是完全同步的。更新界面需要用 Dispatcher.Invoke
__DisplayImagePage();
// 恢复界面也封装成异步方法
await HideBusyStatusAsync();
});
}

private async Task ShowBusyStatusAsync()
{
await Dispatcher.InvokeAsync(() =>
{
textblock1.Visibility = Visibility.Visible;
});
}

private async Task HideBusyStatusAsync()
{
await Dispatcher.InvokeAsync(() =>
{
textblock1.Visibility = Visibility.Hidden;
});
}

C# 长耗时任务更新界面无效的解决方法
https://taylorandtony.github.io/2025/07/01/csharp-WPF-长耗时任务更新界面无效的解决方法/
作者
TaylorAndTony
发布于
2025年7月1日
许可协议