如何使用顶级 Program.cs 在 C# 9 中处理 {STAThread]

How to handle {STAThread] in C# 9 Using Top-Level Program.cs

我刚刚接触 C# 9 并正在尝试实现顶级语句,特别是在无处不在的 Program.cs 中。我在一种情况下成功地做到了这一点,但在第二种情况下,应用程序在 OpenFileDialog() 中获得了 ThreadStateException。

我替换了生成的Program.cs

using System;
using System.Windows.Forms;

namespace MapLines {
    static class Program {
        /// <summary>
        ///  The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main() {
            Application.SetHighDpiMode(HighDpiMode.SystemAware);
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new MainForm());
        }
    }
}

using System.Windows.Forms;
using MapLines;

Application.SetHighDpiMode(HighDpiMode.SystemAware);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm());

这是 OpenFileDialog 中的异常

System.Threading.ThreadStateException
  HResult=0x80131520
  Message=Current thread must be set to single thread apartment (STA) mode before OLE calls can be made. Ensure that your Main function has STAThreadAttribute marked on it. This exception is only raised if a debugger is attached to the process.
  Source=System.Windows.Forms
  StackTrace:
   at System.Windows.Forms.FileDialog.RunDialog(IntPtr hWndOwner)
   at System.Windows.Forms.CommonDialog.ShowDialog(IWin32Window owner)
   at System.Windows.Forms.CommonDialog.ShowDialog()
   at MapLines.MainForm.OnOpenImageClick(Object sender, EventArgs e) in C:\Users\evans\Documents\Visual Studio 2019\Projects\Map Lines\Map Lines\MainForm.cs:line 664
   at System.Windows.Forms.ToolStripItem.RaiseEvent(Object key, EventArgs e)
   at System.Windows.Forms.ToolStripMenuItem.OnClick(EventArgs e)
   at System.Windows.Forms.ToolStripItem.HandleClick(EventArgs e)
   at System.Windows.Forms.ToolStripItem.HandleMouseUp(MouseEventArgs e)
   at System.Windows.Forms.ToolStrip.OnMouseUp(MouseEventArgs mea)
   at System.Windows.Forms.ToolStripDropDown.OnMouseUp(MouseEventArgs mea)
   at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
   at System.Windows.Forms.Control.WndProc(Message& m)
   at System.Windows.Forms.ScrollableControl.WndProc(Message& m)
   at System.Windows.Forms.ToolStrip.WndProc(Message& m)
   at System.Windows.Forms.ToolStripDropDown.WndProc(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
   at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, WM msg, IntPtr wparam, IntPtr lparam)

回到原来的 Program.cs,它有 [STAThread],修复它。

None 我找到的关于 C# 9 新特性的文章提到了这一点。这似乎很重要,因为必须有很多应用程序使用 OpenFileDialog() 并且可能还有其他应用程序。据我了解,Winforms 需要单线程单元 (STA) 线程。当需要 STA 线程时,有没有办法使用顶级语句?

using System.Threading;
using System.Windows.Forms;
using MapLines;

var thread = new Thread(() =>
{
    Application.SetHighDpiMode(HighDpiMode.SystemAware);
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);
    Application.Run(new MainForm());
});
thread.SetApartmentState(ApartmentState.STA);
thread.Start();

有可能,这是看起来 运行 很好的最小示例:

using System.Threading;
using System.Windows.Forms;

// It is unfortunate but we have to set it to Unknown first.
Thread.CurrentThread.SetApartmentState(ApartmentState.Unknown);
Thread.CurrentThread.SetApartmentState(ApartmentState.STA);

Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(defaultValue: false);
Application.SetHighDpiMode(HighDpiMode.PerMonitorV2);

Application.Run(new Form());

来源:这张票来自dotnet/winforms Github:https://github.com/dotnet/winforms/issues/5071