即使在异步状态下,WPF MainWindow也会冻结

时间:2018-01-11 08:52:49

标签: c# wpf multithreading asynchronous mainwindow

我尝试做的是执行由MainWindow上的按钮事件触发的繁重任务,但仍然可以自由拖动窗口。我已经尝试了async / await模式和创建新线程。但是,线程将是非阻塞的,MainWindow仍会冻结。这是代码:

uiTIN.Click += async (o, e) =>
{
    var _ = await Task.Run(() => job());
};

这是按钮回调,这里是func:

    private int job()
    {
        this.Dispatcher.Invoke(() =>
        { 
         //Other function calls here omitted
        });
     return 0;
    }

编辑:解决方法是使用BackgroundWorker,我还在Dispatcher Invoke函数中修饰了相关的UI代码片段

3 个答案:

答案 0 :(得分:2)

来自Dispatcher上的Microsoft's doccumentation(强调我的):

  

在WPF中,DispatcherObject只能由与其关联的Dispatcher访问。例如,后台线程无法更新与UI线程上的Button关联的Dispatcher的内容。 为了让后台线程访问Button的Content属性,后台线程必须将工作委托给与UI线程关联的Dispatcher。这是通过使用InvokeBeginInvoke 来完成的。 Invoke是同步的,BeginInvoke是异步的。该操作将添加到指定Dispatcher的{​​{1}}队列中。

所以基本上你正在做的是调用一个异步方法,然后强制它在UI线程上运行,它什么都不做。

DispatcherPriority中,我认为您需要访问界面的某些部分,如果情况并非如此,您只需删除{{1}从你的方法。

如果我的假设是正确的,那么你必须想出一种分割你的功能的方法,这样不与UI相关的部分在后台线程中运行,而只需要在UI线程上运行的部分实际上做了

我的建议是使用Background Worker。以下是它的外观:

//Other function calls here omitted

......然后......

Dispatcher.Invoke

答案 1 :(得分:0)

通常的做法是你必须尽快从onClick事件回调按钮返回,以避免阻塞主线程(或者某些引用UI线程)。如果主线程被阻止,应用程序将看起来像冻结。这是用于同步UI流的任何GUI应用程序的基本设计。

您在回调中启动异步任务,但在返回之前还要等待任务完成。您应该在onClick事件中启动BackgroundWorker然后返回。

答案 2 :(得分:0)

已经很好地解释了为什么你的代码阻塞了UI线程(在Dispatcher上排队你的工作)。但我不建议使用BackgroundWorker,我宁愿使用Task.Run修复您的代码,原因有几个,本文将对此进行解释:https://blog.stephencleary.com/2013/09/taskrun-vs-backgroundworker-conclusion.html