【问题标题】:How to handle {STAThread] in C# 9 Using Top-Level Program.cs如何使用顶级 Program.cs 在 C# 9 中处理 {STAThread]
【发布时间】:2021-03-04 20:48:20
【问题描述】:

我刚刚进入 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)

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

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

【问题讨论】:

  • 不,需要传统风格。

标签: c# c#-9.0


【解决方案1】:
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();

【讨论】:

  • 不知道为什么目前有反对票。这似乎是合理的并且似乎有效。让我尝试一下,看看是否有任何问题(或者是否有人有更好的想法),我会将其标记为解决方案。使用此解决方案还是使用模板生成的原始版本更好,可能值得商榷,但它回答了我的问题。
  • 我想了很久,目前还没有找到更好的东西(也许C# 9.1+中出现了解决这个问题的东西)。另一个可能的改进是 NuGet 包,它将代码简化为调用 Main.Run(() => {your-code})。
  • 我一直在使用这种方法,它似乎只是工作。从实际的角度来看,我没有看到任何不同的东西。我对此表示赞同。
  • 是的,这行得通……从“哇,C# 9 太棒了,不需要所有样板就可以开始!”的角度来看!这有点让维护者失望。它非常适合不需要 STAThread 的任何东西,但除此之外这不是很棒。
  • 我会在thread.Start() 之后使用thread.Join() 来等待线程完成执行。
【解决方案2】:

有可能,这是似乎运行良好的最小示例:

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

【讨论】:

    猜你喜欢
    • 2010-10-25
    • 1970-01-01
    • 2016-09-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-27
    • 2019-06-01
    • 2022-01-23
    相关资源
    最近更新 更多