WPF - Почему пользовательский интерфейс блокируется? - PullRequest
0 голосов
/ 17 сентября 2018

Если мы используем асинхронный шаблон на основе задач с асинхронными и ожидающими ключевыми словами, проблем с блокировкой пользовательского интерфейса не возникает. Например, мы можем потратить 10 секунд на загрузку данных с сервера и одновременно с радостью отобразить индикатор ожидания. Однако при выполнении сложных задач в потоке пользовательского интерфейса поток блокируется, а анимация в индикаторе ожидания просто зависает.

Конечно, одной из стратегий может быть полное отсутствие здоровенного пользовательского интерфейса, но в данном случае это не совсем вариант. Я загружаю сотни TreeViewItems на экран. Это явно вызывает блокировку пользовательского интерфейса.

Я попытался поместить работу в диспетчер элемента управления следующим образом, но это не помогает:

   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.Run, он на самом деле останавливает блокировку пользовательского интерфейса, но, очевидно, я получаю перекрестное нарушение.

  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);

Есть ли какие-либо идеи о том, как сказать пользовательскому интерфейсу уменьшить приоритет этой работы, чтобы у индикатора ожидания была возможность анимировать, а весь пользовательский интерфейс не блокировался?

1 Ответ

0 голосов
/ 19 сентября 2018

Ответ на мой первоначальный вопрос заключается в том, что Dispatcher (который обрабатывает пересылку сообщений) выполняет все по порядку «первым пришел - первым обслужен» и не является многопоточным.Это означает, что если вы загрузите Dispatcher сообщениями, пользовательский интерфейс будет заблокирован.К счастью, проблему легко решить.Все, что мне нужно сделать, это вызвать

await Dispatcher.Yield(); 

в цикле, и проблема волшебным образом исчезнет.То, что он делает, это позволяет выполнять другую работу пользовательского интерфейса между созданием узлов.

Этот ответ является заполнителем, пока здесь не будет добавлено больше подробностей.

...