我已经使用过Task
类型。当Task
没有返回任何结果时,一切都很好。例如:
<Button Name="_button"
Click="ButtonBase_OnClick">
Click
</Button>
后台代码: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>
:
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线程被锁定,直到任务返回结果。
_button.IsEnabled = false;
因此,上面的字符串将被完全忽略。我在.Net 4.0
上,所以我不能使用async/await
方法。这个问题真让我恶心。有解决方案吗?
你的主线程阻塞了,因为对Task.Result
的调用要等到Task
完成。相反,您可以在完成Task
之后使用Task.ContinueWith()
访问Task.Result
。对TaskScheduler.FromCurrentSynchronizationContext()
的调用导致延续在主UI线程上运行(因此您可以安全地访问_button
)。
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。
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;
}