为什么默认情况下WinForms应用程序是STAThread?

Dan*_*lba 19 .net c# sta winforms

使用Visual Studio 创建空WinForms应用程序时,模板STAThread在主应用程序类中具有该属性.

我一直在阅读一些关于它的文档,但我不确定我是否理解它.

我真的有一些问题:

  1. 为什么要添加此属性?
  2. 这是什么意思?
  3. 如果删除此属性会发生什么?

Ale*_*ort 19

引用MSDN博客,

应用STAThreadAttribute时,它会将当前线程的单元状态更改为单线程.在没有深入讨论COM和线程的情况下,该属性确保了当前线程与可能希望通过COM与之通信的其他线程之间的通信机制.当您使用Windows窗体时,根据您使用的功能,它可能正在使用COM互操作以与操作系统组件进行通信.这方面的好例子是剪贴板和文件对话框.


小智 13

1.为什么要添加此属性?

因为它是ActiveX对象模型所必需的.并且您可以在WinForm上删除ActiveX控件(因此它是为了兼容性)或某些.NET类使用需要该属性的本机控件.

这是什么意思?

这意味着该线程在单线程单元模型中运行.

3.如果删除此属性会怎样?

如果删除该属性,则行为未定义.程序可能会随机失败,有时会出现明智的错误消息.例如,现在可能会有效,然后打破服务包.

  • 不仅仅是 ActiveX 控件,还有很多其他东西都依赖于它。剪贴板、拖放、任何 shell 对话框,如 OpenFileDialog。加上许多在底层使用 COM API 的 .NET 包装器。这就是您看不到但只能在 STA 线程中正常工作的所有 COM 互操作。即使 CLR 也意识到了这一点,例如,当在 UI 线程上调用时,Thread.Join() 会泵出一个消息循环。 (2认同)

小智 5

3.如果删除这个属性会发生什么?

我只是添加一个简单的例子来说明问题。

我创建了带有按钮和 OpenFileDialog 的简单 WinForms 应用程序。单击按钮时,我运行一个显示 openFileDialog 的线程。我在使用和不使用 STAThread 的情况下启动应用程序,单击按钮的结果是相同的 - 它会抛出异常“跨线程操作无效:从创建它的线程以外的线程访问控制‘Form1’”。看起来好像没有什么区别。但不是。

然后我通过调用以下方法更改了 openFileDialog 的显示:

private void ShowOFD()
{
    if (InvokeRequired)
    {
        BeginInvoke(new Action(ShowOFD));
        return;
    }

    openFileDialog1.ShowDialog(this);
}
Run Code Online (Sandbox Code Playgroud)

使用 STAThread,它可以按预期正常工作。如果没有 STAThread,它会抛出异常:“在进行 OLE 调用之前,当前线程必须设置为单线程单元 (STA) 模式。确保您的 Main 函数上标记有 STAThreadAttribute。仅当调试器附加到时才会引发此异常。的过程”。

然后我在没有调试器的情况下多次启动该应用程序(与 Visual Studio 分离)。一次应用程序只是默默关闭,另一次应用程序关闭并显示消息“vshost 已停止工作”