Как запустить асинхронную задачу на WPF без зависания графического интерфейса - PullRequest
2 голосов
/ 11 марта 2019

У меня есть приложение WPF для мониторинга данных, и я пишу Task.Run в методе Loaded для выполнения работы и отображения данных в графическом интерфейсе.

Код выглядит следующим образом:

private async void Window_Loaded(object sender, RoutedEventArgs e)
{

        await Task.Run(() => DoAddAsync());
}

void DoAddAsync()
{

  while (true)

  {
       this.Dispatcher.Invoke(() =>
       {
              //Do Some
       });
  }
}

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

Но если я выполняю метод в this.Dispatcher.Invoke, графический интерфейс зависает, и я ничего не могу сделать, пока этот метод не будет закрыт.

Кто-нибудь может помочь мне запустить метод в this.Dispatcher.Invoke без зависания GUI?

1 Ответ

1 голос
/ 11 марта 2019

Вы можете использовать асинхронный цикл. Хотя это выглядит как бесконечный цикл, на самом деле это не так. Из-за ожидания Задачи задержки этот метод периодически возвращает управление вызывающей стороне. Если бы это был не асинхронный метод с допустимой асинхронной операцией, это был бы синхронный метод, и при его вызове пользователь мог заблокировать пользовательский интерфейс.

Но поскольку это не так, он работает по мере необходимости и дает вам четкое представление о том, что должен делать код, а также поддерживает нас в потоке пользовательского интерфейса все время (магия ожидания!), Поэтому мы не имеет многопоточных проблем или нескольких делегатов / обратных вызовов.

private async Task DoAddAsync()
{
    while (true)
    {
        // do the work in the loop
        // ....
        // don't run again for at least 200 milliseconds
        await Task.Delay(200);
    }
}

Реальная хитрость в том, чтобы сделать эту работу, заключается не в методе DoAddAsync. Это как мы это называем. Вы не ждете звонка.

private async void Window_Loaded(object sender, RoutedEventArgs e)
{
     DoAddAsync()
}

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

private async void Window_Loaded(object sender, RoutedEventArgs e)
{
    await Task.Run(async () =>
    {
        while (true)
        {
            // do the work in the loop

            // update the UI on the UI thread
            Dispatcher.Invoke(() => // do some );

            // don't run again for at least 200 milliseconds
            await Task.Delay(200);
        }
    });
}
...