WPF异步任务< T>封锁使用者介面 [英] WPF asynchronous Task<T> blocking UI

查看:74
本文介绍了WPF异步任务< T>封锁使用者介面的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经使用过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异步任务&lt; T&gt;封锁使用者介面的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆