【问题标题】:How to create a task (TPL) running a STA thread?如何创建运行 STA 线程的任务 (TPL)?
【发布时间】:2011-08-23 17:20:06
【问题描述】:

使用线程非常简单

 Thread thread = new Thread(MethodWhichRequiresSTA);
 thread.SetApartmentState(ApartmentState.STA);  

如何在 WPF 应用程序中使用任务来完成相同的任务?这是一些代码:

Task.Factory.StartNew
  (
    () => 
    {return "some Text";}
  )
   .ContinueWith(r => AddControlsToGrid(r.Result));  

我收到了一个 InvalidOperationException

调用线程必须是 STA,因为很多 UI 组件都需要这个。

【问题讨论】:

标签: c# wpf multithreading thread-safety task-parallel-library


【解决方案1】:

Dispatcher.Invoke 可能是一个解决方案。例如

    private async Task<bool> MyActionAsync()
    {
        // await for something, then return true or false
    }
    private void StaContinuation(Task<bool> t)
    {
        myCheckBox.IsChecked = t.Result;
    }
    private void MyCaller()
    {
        MyActionAsync().ContinueWith((t) => Dispatcher.Invoke(() => StaContinuation(t)));
    }

【讨论】:

  • ContinueWithDispatcher 在 async/await 出现后被认为是老派的方法。我会避免将它们用于新的开发(一般而言)。
【解决方案2】:

您可以使用TaskScheduler.FromCurrentSynchronizationContext Method 为当前同步上下文(运行 WPF 应用程序时的 WPF 调度程序)获取TaskScheduler

然后使用接受 TaskScheduler 的 ContinueWith 重载:

var scheduler = TaskScheduler.FromCurrentSynchronizationContext();

Task.Factory.StartNew(...)
            .ContinueWith(r => AddControlsToGrid(r.Result), scheduler);

【讨论】:

  • 只是为了清楚;只有 ContinueWith 方法中的 lambda 会在正确的上下文中运行,而不是在主任务 lambda 中运行。
  • 谢谢,我正在尝试TaskScheduler.Current(来自 WinForms 按钮事件处理程序),不明白为什么它不起作用...
  • 作为一个澄清点,实例方法 Task.Start() 也有一个重载,它接受一个 TaskScheduler。问题的细节清楚地表明我们对继续情况更感兴趣,但更一般的问题是如何在 STA 线程上运行任务并不仅限于这种情况。一开始我错误地认为我需要从一个空的“软糖”任务继续,才能运行我想要的 STA 任务。
  • 所以不应该编辑这个问题的标题以更好地反映其意图吗?
  • 或者分解成两个。 “如何在 STA 线程上启动任务”和“如何在 STA 线程上继续任务”。
猜你喜欢
  • 1970-01-01
  • 2011-06-01
  • 2014-09-17
  • 2015-07-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-19
相关资源
最近更新 更多