WPF 异步 Task<T> 阻塞 UI

标签 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方法。
这个问题真的让我恶心……有解决方案吗?

最佳答案

您的主线程被阻塞,因为调用 Task.Result等到Task已经完成。相反,您可以使用 Task.ContinueWith()访问 Task.ResultTask已经完成。调用 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;      
}

关于WPF 异步 Task<T> 阻塞 UI,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23934236/

相关文章:

c# - 如何在 Windows 10 中打开显示设置(语法上,特别是使用 C#)?

wpf - UI自动化测试右键菜单

c++ - Chrome 嵌入式检测按钮按下

c# - 如何将 C# GUI 标签文本分成单独的行(不在运行时)?

magento - 在 Controller 中添加新 block 并将其设置在第一个位置

ios - Apple 文档示例代码中的 __block 是什么意思?

c# - 将属性绑定(bind)到 itemssource 集合的属性

wpf - 将 WPF 日期选择器的默认日期设置为当前日期

wpf - 命令绑定(bind) - 即使在 WPF 应用程序中关闭窗口后也会调用 CanExecute()

sql-server - SQL Server 中许多操作超时并阻塞进程