代码之家  ›  专栏  ›  技术社区  ›  Damian Radinoiu

WPF主窗口即使在异步状态下也会冻结

  •  -1
  • Damian Radinoiu  · 技术社区  · 7 年前

    我想做的是执行由主窗口上的按钮事件触发的繁重任务,但仍然能够自由拖动窗口。我尝试了异步/等待模式和创建新线程。然而,线程将是非阻塞的,主窗口仍然冻结。代码如下:

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

    这是按钮回调,下面是函数:

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

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

    3 回复  |  直到 7 年前
        1
  •  2
  •   appa yip yip    7 年前

    从…起 Microsoft's doccumentation 调度员(重点矿井):

    在WPF中,a DispatcherObject 只能通过访问 Dispatcher 它与关联。例如,后台线程无法更新 Button 调度员 在UI线程上。 以便后台线程访问 Content 属性,后台线程必须将工作委托给 调度员 与UI线程关联。这可以通过使用 Invoke BeginInvoke . 援引 是同步的,并且 异步调用 是异步的。该操作将添加到 调度员 在指定的 DispatcherPriority .

    因此,基本上您要做的是调用一个异步方法,然后强制它在UI线程上运行,这将一事无成。

    在您的 //Other function calls here omitted ,我想你需要访问UI的某些部分,如果不是这样,你所要做的就是删除 Dispatcher.Invoke 从您的方法。

    如果我的假设是正确的,那么您必须找到一种分割函数的方法,以便与UI无关的部分在后台线程中运行,并且只需要在UI线程上运行真正需要的部分。

    我的建议是使用 Background Worker . 下面是它的外观:

    uiTIN.Click += (o, e) =>
    {
        job();
    };
    

    ... 然后。。。

    private int job()
    {
        BackgroundWorker worker = new BackgroundWorker();
    
        worker.DoWork += (s, e) =>
        {
            // Part of other function calls here omitted that don't need to run on the UI thread
    
            Dispatcher.Invoke(() =>
            {
                // Part of other function calls here omitted that must run on the UI thread
            });
        };
    
        worker.RunWorkerAsync();
    
        return 0;
    }
    
        2
  •  0
  •   Gordon    7 年前

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

    您可以在回调中启动异步任务,但也可以等待任务完成后再返回。你应该开始 BackgroundWorker 在onClick事件中,然后返回。

        3
  •  0
  •   Stefano d'Antonio    7 年前

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