如果您在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 应用程序来说都是一种非常自然的架构。