WPF - 为什么UI锁定?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了WPF - 为什么UI锁定?相关的知识,希望对你有一定的参考价值。

如果我们使用基于任务的异步模式与async和await关键字,则UI锁定没有问题。例如,我们可以花10秒钟从服务器加载数据,并愉快地同时显示等待指示器。但是,在UI线程上运行复杂任务时,线程会锁定,等待指示器中的动画会冻结。

当然,一种策略可能是完全避免大量的UI,但在这种情况下,这不是一个真正的选择。我正在将数百个TreeViewItem加载到屏幕上。这显然导致UI锁定。

我已经尝试将这项工作放在控件的Dispatcher上,但它没有帮助:

   var action = new Action(() =>
    {

       SchemaTree.Items.Clear();

       foreach (var assemblyStructure in assemblyStructures)
       {
           var assemblyNode = CreateTreeNode(SchemaTree.Items, assemblyStructure.Assembly.Name.Replace("Adapt.Model.", string.Empty), assemblyStructure.Assembly, "/Icons/Schema.PNG");

           foreach (var theNameSpace in assemblyStructure.Namespaces)
           {
               var namespaceNode = CreateTreeNode(assemblyNode.Items, theNameSpace.TheNamespace.Name, theNameSpace.TheNamespace, "/Icons/Namespace.PNG");

               foreach (var classInfo in theNameSpace.Classes)
               {
                   CreateClassInfoNode(theNameSpace, classInfo, namespaceNode);
               }
           }
       }
   });

    await SchemaTree.Dispatcher.BeginInvoke(action, DispatcherPriority.Background, null);

如果我将工作转移到Task with Task.Run,​​它实际上会阻止UI锁定,但很明显,我遇到了一个交叉线程违规。

  var action = new Action(async () =>
        {
            await Task.Run(() =>
            {
                SchemaTree.Items.Clear();

                foreach (var assemblyStructure in assemblyStructures)
                {
                    var assemblyNode = CreateTreeNode(SchemaTree.Items, assemblyStructure.Assembly.Name.Replace("Adapt.Model.", string.Empty), assemblyStructure.Assembly, "/Icons/Schema.PNG");

                    foreach (var theNameSpace in assemblyStructure.Namespaces)
                    {
                        var namespaceNode = CreateTreeNode(assemblyNode.Items, theNameSpace.TheNamespace.Name, theNameSpace.TheNamespace, "/Icons/Namespace.PNG");

                        foreach (var classInfo in theNameSpace.Classes)
                        {
                            CreateClassInfoNode(theNameSpace, classInfo, namespaceNode);
                        }
                    }
                }
            });

        });


        await SchemaTree.Dispatcher.BeginInvoke(action, DispatcherPriority.Background, null);

关于如何告诉UI减少这项工作的优先级以使等待指示器有机会动画,以及整个UI没有锁定的任何想法?

答案

我原来问题的答案是Dispatcher(处理消息泵送)以先进先出顺序执行所有操作,而不是多线程。这意味着如果您使用消息填充Dispatcher,UI将锁定。值得庆幸的是,问题很容易解决。我需要做的就是打电话

await Dispatcher.Yield(); 

在循环中,问题神奇地消失了。它的作用是允许在创建节点之间执行其他UI工作。

此答案是占位符,直到此处添加更多详细信息。

以上是关于WPF - 为什么UI锁定?的主要内容,如果未能解决你的问题,请参考以下文章

是否需要锁定阅读对象?

附加 Visual Studio 调试器会导致高 CPU 使用率和 UI 线程锁定

WPF数据绑定到图像文件永远锁定该文件[重复]

多线程更新UI的常用方法

如何在不锁定活动方向的情况下锁定片段方向?

有啥方法可以停止 WPF 的 UI 窗口实例