WPF TextBlock 仅在所有工作完成后才显示所有日志消息
Posted
技术标签:
【中文标题】WPF TextBlock 仅在所有工作完成后才显示所有日志消息【英文标题】:WPF TextBlock shows all log messages only after all work is done 【发布时间】:2017-03-29 17:04:34 【问题描述】:当用户单击Execute
按钮时,我想做一些事情并逐步将日志消息输出到TextBlock
- 这样用户就可以看到当前正在发生的事情。
问题是我的TextBlock
在所有工作完成后更改了它的内容(为时已晚)。如何在处理过程中强制 WPF 重新绘制自身?
代码如下:
private void btn_execute_Click(object sender, RoutedEventArgs e)
.... stuff ....
我尝试在对TextBlock
进行任何更改后添加output_log.InvalidateVisual();
,但没有按预期工作。
【问题讨论】:
你为什么要在后面的代码中这样做?你没有使用 MVVM 吗? 【参考方案1】:如果您在Button
的Click
处理程序中运行同步代码,则此代码将在Dispatcher
线程中执行,从而阻止Dispatcher
运行任何其他代码,例如显示消息的更改在TextBlock
。
有(至少)三种可能的方法来解决这个问题。
首先,您可以在另一个Thread
、Task
或async
事件处理程序中运行您的Execute
代码,并使用Dispatcher
设置Text
:
private async void btn_execute_Click(object sender, RoutedEventArgs e)
for (int i = 0; i < 100; i++)
// Simulate doing some stuff...
await Task.Delay(100);
// Thanks to async/await the current context is captured and
// switches automatically back to the Dispatcher thread after the await.
output_log.Text += i + ", ";
// If you were using Task.Run() instead then you would have to invoke it manually.
// Dispatcher.Invoke(() => output_log.Text += i + ", ");
主要优点是您不会阻止Dispatcher
- 强烈建议您执行所有操作。
第二,您可以继续在Dispatcher
中执行Execute
代码,但是每次要刷新文本时都必须“刷新”Dispatcher
,所以它可以处理所有等待的 UI 操作:
private void btn_execute_Click(object sender, RoutedEventArgs e)
for (int i = 0; i < 100; i++)
// Simulate doing some stuff...
Thread.Sleep(100);
output_log.Text += i + ", ";
Dispatcher.Invoke(DispatcherPriority.Background, new Action(() => ));
这当然是可能的,但我真的不推荐。
或第三个,
您可以将MVVM
用于您的架构,
在async
事件处理程序(或Command
)中运行您的Execute
代码,
仅更改ViewModel
的LogText
属性和
使用数据绑定将TextBlock.Text
绑定到此MyLogViewModel.LogText
属性。
很遗憾,我无法为您提供此场景的快速示例代码,但肯定值得考虑一下,因为MVVM
对任何类型的 WPF 应用程序来说都是一种非常自然的架构。
【讨论】:
以上是关于WPF TextBlock 仅在所有工作完成后才显示所有日志消息的主要内容,如果未能解决你的问题,请参考以下文章