WPF-为什么UI锁定?

时间:2018-09-17 03:24:03

标签: wpf multithreading locking dispatcher unresponsive-progressbar

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

当然,一种策略可能是完全避免使用笨拙的UI,但是在这种情况下,这并不是真正的选择。我正在将数百个TreeViewItems加载到屏幕上。显然,这会导致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.Task的Task上,则实际上阻止了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不会锁定?

1 个答案:

答案 0 :(得分:0)

我的原始问题的答案是分派器(处理消息泵送)以先进先出的顺序执行所有操作,并且不是多线程的。这意味着,如果您向Dispatcher充斥消息,则UI将被锁定。值得庆幸的是,这个问题很容易解决。我需要做的就是致电

await Dispatcher.Yield(); 

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

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