我已使用Task
类型。一切都很好,而Task
什么也没有回报。例如:
XAML:
<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
方法。
这个问题真的让我感到恶心......有解决方案吗?
答案 0 :(得分:6)
您的主要帖子正在阻止,因为对Task.Result
的调用会一直等到Task
完成。相反,您可以使用Task.ContinueWith()
在Task.Result
完成之后访问Task
。对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;
}