Задача не работает, если фоновый метод требует пользовательского интерфейса: вызывающий поток должен быть STA, потому что многие компоненты пользовательского интерфейса требуют этого - PullRequest
0 голосов
/ 26 февраля 2020

У меня есть один метод Asyn c, который выполняет различные операции.

 public async void OnClickPublish( )
        {

            Loader loader = new Loader();
            loader.Show();
            await Task.Run(() => PublishSlides(loader));
        }


 private async Task PublishSlides(Loader loader)
        {

        await loader.Dispatcher.Invoke(async () =>
         { 

            loader.LoaderMessage("Opration 1 start..");
            List<SlideProperties> DBList= await Task.Run(() => 
            objSlideImg.DBOpration()); //UI Not needed. work nice



           var cloudTask = SendToCloudAsync(DBList);  
           await cloudTask.ContinueWith(task =>
           {
             if (task.IsFaulted)
              {
                 loader.LoaderMessage(task.Exception.Message + " problem occur in cloud publish");
                  return;
              } 

              loader.ShowSuccess("broadcasting..");
            }, uiScheduler);

        } 
        }


    /*PROBLEM OCCUR IN THIS METHOD*/
      public async Task<bool> SendToCloudAsync(List<SlideProperties> DBList)
        {
            **DashboardUI dashboard= new DashboardUI();**  /* giving issue The calling thread must be STA, because many UI components require this.*/
            dashboard.ShowDashboard()
        }

Поэтому, когда я вызываю методы SendToCloudAsyn c (), это вызывает проблему Вызов поток должен быть STA, поскольку это требуется для многих компонентов пользовательского интерфейса. SendToCloudAsyn c () этот метод покажет панель мониторинга моего приложения.

1 Ответ

0 голосов
/ 26 февраля 2020

Я настоятельно рекомендую отделить код пользовательского интерфейса от фонового кода и сделать так, чтобы уровень пользовательского интерфейса «управлял» бизнес / фоновым кодом.

В настоящее время OnClickPublish вызывает PublishSlides в фоновом потоке (Task.Run ), а затем PublishSlides немедленно возвращается к потоку пользовательского интерфейса (Dispatcher.Invoke) и запускает все тело метода в потоке пользовательского интерфейса. Это ничего не дает - просто перепрыгивая через потоки.

Чтобы правильно отделить пользовательский интерфейс от фонового кода потока, есть два основных метода и один менее распространенный метод.

Первый основной Техника заключается в использовании возвращаемых значений. Вместо того чтобы метод извлекал / вычислял данные, а затем обновлял пользовательский интерфейс с результатами результатов, просто попросите его извлечь / вычислить данные и вернуть . Затем вызывающий поток может решить, должен ли поиск / расчет выполняться в фоновом потоке (Task.Run), а затем поместить данные в пользовательский интерфейс.

Второй основной метод заключается в использовании обновлений прогресса. Вместо того, чтобы «рабочий» метод доходил до пользовательского интерфейса и обновлял ход выполнения напрямую, он должен использовать IProgress<T> для отчета о ходе выполнения. Затем вызывающий метод может решить, должна ли «работа» выполняться в фоновом потоке (Task.Run), и он может передать реализацию выполнения (например, Progress<T>), которая выполняет обновления прогресса в потоке пользовательского интерфейса.

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

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

public async void OnClickPublish()
{
  Loader loader = new Loader();
  loader.Show();
  PublishSlides(loader);
}

private async Task PublishSlides(Loader loader)
{
  loader.LoaderMessage("Opration 1 start..");
  List<SlideProperties> DBList = await Task.Run(() => objSlideImg.DBOpration());

  try
  {
    await SendToCloudAsync(DBList);
    loader.ShowSuccess("broadcasting..");
  }
  catch (Exception ex)
  {
    loader.LoaderMessage(ex.Message + " problem occur in cloud publish");
  } 

  DashboardUI dashboard = new DashboardUI();
  dashboard.ShowDashboard();
}

public async Task<bool> SendToCloudAsync(List<SlideProperties> DBList)
{
  ...
}
...