WPF异步任务<t>阻止UI </t>

时间:2014-05-29 13:14:31

标签: wpf user-interface block task

我已使用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方法。 这个问题真的让我感到恶心......有解决方案吗?

1 个答案:

答案 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;      
}