Универсальный Windows отклик пользовательского интерфейса с асинхронностью / ожиданием - PullRequest
0 голосов
/ 28 мая 2020

Пожалуйста, помогите мне понять, как правильно ожидать длительное выполнение задач, чтобы пользовательский интерфейс оставался отзывчивым в приложении Universal Windows.

В приведенном ниже коде OperateSystem - это класс модели, который наследует ObservableObject. OperateSystem.GetLatestDataFromAllDevices подключается к множеству инструментов, собирает данные и обновляет свойства классов с помощью информации от инструментов. Представления обновляются значениями из операционной системы.

Пользовательский интерфейс не отвечает, пока выполняется задача dispatcher.RunAsyn c, я добавил Thread.Sleep (5000) в GetLatestDataFromAllDevices (), чтобы убедиться, и он блокирует пользовательский интерфейс на 5 секунд. Без await Task.Delay (refreshTimer) пользовательский интерфейс никогда не обновляется (я предполагаю, что он мгновенно возвращается в GetLatestDataFromAllDevies до того, как пользовательский интерфейс сможет обновиться). Установка параметра refreshTimer на 1 мс позволяет обновлять пользовательский интерфейс, но я знаю, что это обходной путь для другой проблемы, которую необходимо исправить. mnet методы подключаются к прибору, собирают данные, выполняют некоторое масштабирование / форматирование и обновляют свойство класса с текущим значением.

Я следил за другими ответами SO, чтобы использовать dispatcher.RunAsyn c, используя другие методы asyn c, я бы получил ошибки потокового сшивания. Но теперь я думаю, что диспетчер в любом случае просто маршалирует эти задачи в потоке пользовательского интерфейса, поэтому он по-прежнему блокирует обновления пользовательского интерфейса.

Чтобы воссоздать ошибки маршаллинга потоков, я сделал GetLatestDataFromAllDevices asyn c и ожидал выполнения метода как задачи.

    internal async void GetLatestDataFromAllDevices(ConfigurationSettings configurationSettings)
    {
        await Task.Run(()=>GetDataInstrument1(configurationSettings));
        GetDataInstrument2(configurationSettings);
        GetDataInstrument3(configurationSettings);
        GetDatainstrumetn4(configurationSettings);
    }

Это приводит к: System.Exception: 'Приложение вызвало интерфейс, который был упорядочен для другого потока. (Исключение из HRESULT: 0x8001010E (RPC_E_WRONG_THREAD)) '

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

1 Ответ

2 голосов
/ 28 мая 2020
• 1000 Если пользовательский интерфейс не отвечает, вы должны передать sh работу фоновому потоку (например, Task.Run).

Для сортировки обновлений обратно в поток пользовательского интерфейса я рекомендую (в порядке предпочтения):

  1. Использование возвращаемого значения асинхронных методов. Например, MyUiProperty = await Task.Run(() => MyBackgroundMethod(...));.
  2. Использование Progress<T> для получения нескольких значений из асинхронных методов. Например, var progress = new Progress<string>(update => MyUiProperty = update); await Task.Run(() => MyBackgroundMethod(..., progress));.
  3. Захват SynchronizationContext в фоновых классах и использование его для отправки обновлений в поток пользовательского интерфейса. Это наименее рекомендуется, потому что это приводит к тому, что ваш фон управляет вашим пользовательским интерфейсом, а не наоборот.
...