WPF异步任务< T>封锁使用者介面 [英] WPF asynchronous Task<T> blocking UI
问题描述
我已经使用过Task
类型.当Task
不返回任何内容时,一切都很好.例如:
I already worked with Task
type. And all was good while Task
return nothing. For example:
XAML:
<Button Name="_button"
Click="ButtonBase_OnClick">
Click
</Button>
CodeBehind:
CodeBehind:
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
_button.IsEnabled = false;
Task.Factory.StartNew(() =>
{
Thread.Sleep(5*1000);
Dispatcher.Invoke(new Action(() => _button.IsEnabled = true));
});
}
这很好.但是我要Task
返回一些值,例如Boolean
.所以我需要使用Task<Boolean>
:
This works fine. But I want to Task
returns some value, for example Boolean
. So I need to use Task<Boolean>
:
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
_button.IsEnabled = false;
var task = Task<Boolean>.Factory.StartNew(() =>
{
Thread.Sleep(5*1000);
return true;
});
if (task.Result)
_button.IsEnabled = true;
}
在这里,我们遇到了UI阻塞的问题. UI线程被锁定,直到任务将返回结果为止.
And here we have a problem with UI blocking. UI thread is locked untill task will return result.
_button.IsEnabled = false;
因此,上面的字符串被完全忽略.
我在.Net 4.0
上,所以我不能使用async/await
方法.
这个问题真的让我感到恶心...解决了吗?
So, string above is completely ignored.
I am on .Net 4.0
, so I cannot use async/await
approach.
This problem really makes me sick... Has it solution?
推荐答案
您的主线程正在阻塞,因为对Task.Result
的调用一直等到Task
完成.相反,您可以在Task
完成后使用Task.ContinueWith()
访问Task.Result
.调用TaskScheduler.FromCurrentSynchronizationContext()
会使延续在主UI线程上运行(因此您可以安全地访问_button
.)
Your main thread is blocking because the call to Task.Result
waits until the Task
has completed. Instead you can use Task.ContinueWith()
to access the Task.Result
after the Task
has completed. The call to TaskScheduler.FromCurrentSynchronizationContext()
causes the continuation to run on the main UI thread (so you can access _button
safely).
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
_button.IsEnabled = false;
Task<Boolean>.Factory.StartNew(() =>
{
Thread.Sleep(5*1000);
return true;
}).ContinueWith(t=>
{
if (t.Result)
_button.IsEnabled = true;
}, TaskScheduler.FromCurrentSynchronizationContext());
}
更新
如果您使用的是C#5,则可以改用async/await.
If you are using C# 5 you can use async/await instead.
private async void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
_button.IsEnabled = false;
var result = await Task.Run(() =>
{
Thread.Sleep(5*1000);
return true;
});
_button.IsEnabled = result;
}
这篇关于WPF异步任务< T>封锁使用者介面的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!