从UI线程执行Task.Run会引发STA错误 [英] Task.Run from UI thread throws STA error

查看:92
本文介绍了从UI线程执行Task.Run会引发STA错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我使用Office.Interop库重构一些旧的C#代码以生成文档时,我发现了这一点,并且由于它在调用函数时使用UI上下文而阻塞了它

While I was refactoring some old C# code for document generation with Office.Interop library I found this and because of it was using UI context when function were called from it it was blocking it

示例

private void btnFooClick(object sender, EventArgs e)
{
      bool documentGenerated = chckBox.Checked ? updateDoc() : newDoc();

      if(documentGenerated){
        //do something
      }
}

决定进行更改,以减少阻止用户界面的行为

Decided to change it like that to reduce from blocking UI

private async void btnFooClick(object sender, EventArgs e)
{
      bool documentGenerated; = chckBox.Checked ? updateDoc() : newDoc();

      if(chckBox.Checked)
      {
                documentGenerated = await Task.Run(() => updateDoc()).ConfigureAwait(false);
      }
      else
      {
                documentGenerated = await Task.Run(() => newDoc()).ConfigureAwait(false);
      }

      if(documentGenerated){
        //do something
      }
}

它抛出了这样的错误

当前线程必须设置为单线程单元(STA)模式 可以进行OLE调用之前

Current thread must be set to single thread apartment (STA) mode before OLE calls can be made

为什么会发生这种情况以及可能的解决方法?

Why does it happen and what is possible workaround?

推荐答案

通过Interop访问的COM组件要求调用线程是STA线程,但在您的情况下不是STA.使用STA可以通过多个线程访问该组件.您可以在了解和使用COM线程模型中了解有关为什么需要STA的更多信息. a>您可以按照 answer 中的建议,在Task类上创建扩展方法通过使用任务的Interop来实现COM组件.

The COM components accessed through Interop require the calling thread to be a STA thread but in your case it is not STA. Using STA the component could be accessed through multiple threads. You can read more about why STA is required in Understanding and Using COM Threading Models You can make a extention method on Task class as suggested in this answer to call the COM component through Interop using task.

public static Task<T> StartSTATask<T>(Func<T> func)
{
    var tcs = new TaskCompletionSource<T>();
    Thread thread = new Thread(() =>
    {
        try
        {
            tcs.SetResult(func());
        }
        catch (Exception e)
        {
            tcs.SetException(e);
        }
    });
    thread.SetApartmentState(ApartmentState.STA);
    thread.Start();
    return tcs.Task;
}

您还可以使用Thread代替task,您必须像thread.SetApartmentState(ApartmentState.STA)

You can also use Thread instead of task, you have to set the ApartmentState to STA like thread.SetApartmentState(ApartmentState.STA)

这篇关于从UI线程执行Task.Run会引发STA错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆