首页 > 解决方案 > 如果后台方法需要 UI,则任务不起作用:调用线程必须是 STA,因为许多 UI 组件都需要这个

问题描述

我有一种执行不同操作的异步方法。

 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()
        }

所以当我调用 SendToCloudAsync() 方法时,它会给出问题调用线程必须是 STA,因为许多 UI 组件都需要这个。SendToCloudAsync() 这个方法将显示我的应用程序的仪表板。

标签: c#wpfasync-awaittask

解决方案


我强烈建议将 UI 代码与后台代码分开,并让 UI 层“驱动”业务/后台代码。

目前,在后台线程 ( ) 上OnClickPublish调用,然后立即跳回 UI 线程 ( ) 并在 UI 线程上运行其整个方法体。这并没有完成任何事情——只是在线程之间来回跳跃。PublishSlidesTask.RunPublishSlidesDispatcher.Invoke

要正确地将 UI 与后台线程代码分开,有两种主要技术和一种不太常见的技术。

第一个主要技术是使用返回值。与其让一个方法检索/计算数据,然后用数据结果更新 UI,不如让它检索/计算数据并返回它。然后调用线程可以决定检索/计算是否应该在后台线程(Task.Run)上,然后将数据放在 UI 上。

第二个主要技术是使用进度更新。与其让“工作”方法进入 UI 并直接更新进度,不如使用它IProgress<T>来报告进度。然后调用方法可以决定“工作”是否应该在后台线程(Task.Run)上运行,并且它可以传递一个Progress<T>在 UI 线程上执行进度更新的进度实现(例如,)。

不太常见的技术是从持续运行的后台操作中主动更新 UI。我建议使用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)
{
  ...
}

推荐阅读