如何创建运行STA线程的任务(TPL)?


75

使用线程非常简单

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

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

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

我收到一个InvalidOperationException与

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

Answers:


75

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

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

var scheduler = TaskScheduler.FromCurrentSynchronizationContext();

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

10
只是为了清楚起见;只有ContinueWith方法中的lambda会在适当的上下文中运行,而不是在主任务lambda中运行的上下文。
dudeNumber4

为此,我正在尝试TaskScheduler.Current(从WinForms按钮事件处理程序中),无法理解为什么它不起作用...
Benjol 2012年

11
需要澄清的是,使用TaskScheduler的实例方法Task.Start()也有一个重载。问题的细节清楚地表明,我们对延续情况更感兴趣,但是关于如何在STA线程上运行Task的更一般性的问题不仅限于这种情况。我一开始错误地假设我将需要从一个空的“ fudge”任务中继续才能运行所需的STA任务。
2014年

2
因此,是否应该编辑该问题的标题以更好地反映其意图?
Mrchief

或分为两部分。“如何在STA线程上启动任务”和“如何在STA线程上继续任务”。
大卫,


0

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

在异步/等待出现之后,ContinueWith和和Dispatcher被认为是过时的方法。我会避免将它们用于新开发(通常)。
Theodor Zoulias
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.