如果我们将基于任务的异步模式与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不会锁定?
答案 0 :(得分:0)
我的原始问题的答案是分派器(处理消息泵送)以先进先出的顺序执行所有操作,并且不是多线程的。这意味着,如果您向Dispatcher充斥消息,则UI将被锁定。值得庆幸的是,这个问题很容易解决。我需要做的就是致电
await Dispatcher.Yield();
在循环中,问题神奇地消失了。它的作用是允许其他UI工作在创建节点之间执行。
此答案是一个占位符,直到在此处添加更多详细信息为止。