这个问题在这里以多种方式被问到了,但我找不到一个明确的答案,我有一个简单的代码,一个Button
,一个Textbox
和一个{{1尽管是ButtonClickEventHandler
,后者仍保持UI阻塞,代码:
Async
Xaml:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private async void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
Task t = new Task(() =>
{
for (int i = 0; i < 10000; i++)
{
Dispatcher.Invoke((()=>
{
TextBox.Text += i.ToString();
}));
}
});
t.Start();
await t;
//Something else
}
}
首先,为什么会发生这种情况? 其次,我应该做些什么来使UI保持正常工作而不会挂起,总是遵循这个逻辑。
答案 0 :(得分:5)
定义“阻止”。您发布的代码将不阻止用户界面。但它肯定会让它真的很忙,这很可能会影响看似就好像被阻挡了一样。就此而言,即使不是真的,也要阻止它用于所有实际目的。
您基本上是在GUI线程上执行拒绝服务攻击。你有一个紧密循环的辅助线程,只是继续在GUI线程上执行东西。不要这样做,事情会好得多。
答案 1 :(得分:5)
正如其他人所说,如果您过于频繁地更新用户界面,最终会阻止用户互动。
就您的代码而言,您应该使用Task.Run
而不是任务构造函数,而IProgress<T>
代替Dispatcher.Invoke
。我有IProgress<T>
implementation that handles throttling for you,可以这样使用:
private async void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
using (var progress = ObservableProgress<int>.CreateForUi(value => UpdateUi(value)))
{
await Task.Run(() => BackgroundOperation(progress));
}
...
}
private static void UpdateUi(int progressUpdate)
{
TextBox.Text += progressUpdate.ToString();
}
private static void BackgroundOperation(IProgress<int> progress)
{
for (int i = 0; i < 10000; i++)
{
if (progress != null)
progress.Update(i);
}
}
不需要人为延误。