本文概述
如果你的應用程序運行一段代碼, 該代碼觸發以下ThreadStateException異常:
System.Threading.ThreadStateException:’必須先將當前線程設置為單線程單元(STA)模式, 然后才能進行OLE調用。確保你的Main函數上已標記STAThreadAttribute。僅當將調試器附加到進程時, 才會引發此異常。
在本文中, 我們將向你簡要說明如何防止此異常出現在WinForms項目中。
異常示例
在我們的項目中, 我們使用CefSharp庫, 該庫允許我們使用HTML, CSS和JavaScript創建桌面應用程序。它的功能之一是可以將C#類暴露給窗口中的JavaScript對象。我們具有以下類, 該類顯示用於保存文件的本機對話框(showOpenDialog函數):
using System; using CefSharp.WinForms; using System.IO; using System.Diagnostics; using System.Windows.Forms; using System.Threading; using System.Text; namespace MyApplication { class WindowsTools { // Declare a local instance of chromium and the main form in order to execute things from here in the main thread private static ChromiumWebBrowser _instanceBrowser = null; // The form class needs to be changed according to yours private static Form1 _instanceMainForm = null; public WindowsTools(ChromiumWebBrowser originalBrowser, Form1 mainForm) { _instanceBrowser = originalBrowser; _instanceMainForm = mainForm; } // When this method is called like this, it will throw the exception public void showOpenFile() { OpenFileDialog saveFileDialog1 = new OpenFileDialog(); saveFileDialog1.Filter = "JSON Files (*.json)|*.json"; saveFileDialog1.FilterIndex = 2; saveFileDialog1.RestoreDirectory = true; if (saveFileDialog1.ShowDialog() == DialogResult.OK) { } } } }
如果從JavaScript上下文(CefSharp線程)執行該函數, 則將觸發異常, 因為我們正在CefSharp的默認Apartment State內部運行代碼。
解決辦法
默認情況下, 主應用程序線程初始化為ApartmentState.MTA。將主應用程序線程的公寓狀態設置為ApartmentState.STA的唯一方法是將STAThreadAttribute屬性應用於入口點方法。在我們的例子中, 使用從CefSharp中注冊的類啟動OpenFileDialog的方法, 如果在不更改線程的單元狀態的情況下運行代碼, 將引發異常。
如果你不控制線程的創建(例如CefSharp), 則以下解決方案是最佳解決方案, 你可以創建一個臨時線程並在其中運行代碼:
using System.Threading; string selectedPath = ""; Thread t = new Thread((ThreadStart)(() => { OpenFileDialog saveFileDialog1 = new OpenFileDialog(); saveFileDialog1.Filter = "JSON Files (*.json)|*.json"; saveFileDialog1.FilterIndex = 2; saveFileDialog1.RestoreDirectory = true; if (saveFileDialog1.ShowDialog() == DialogResult.OK) { selectedPath = saveFileDialog1.FileName; } })); // Run your code from a thread that joins the STA Thread t.SetApartmentState(ApartmentState.STA); t.Start(); t.Join(); // e.g C:\Users\MyName\Desktop\myfile.json Console.WriteLine(selectedPath);
有關此異常的更多信息, 我們也建議你閱讀StackOverflow上的此問題。