26

尝试使用 FolderBrowserDialog 时出现以下异常: System.Threading.ThreadStateException: 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.

我已经广泛搜索了这个问题,每个人建议的解决方案似乎是放在[STAThreadAttribute]Main 方法之上,从 Debug 文件夹中删除所有 dll,或者使用该Invoke方法。我已经尝试了所有这些,但我仍然得到同样的例外。

这是代码:

public partial class Form1 : Form
{
    public event EventHandler ChooseLocationHandler = null;

    public string DestFolder
    {
        set { textBox1.Text = value; }
        get { return textBox1.Text; }
    }

    public Form1()
    {
        InitializeComponent();
    }

    private void ChooseLocationButton_Click(object sender, EventArgs e)
    {
        if (ChooseLocationHandler != null)
            ChooseLocationHandler(this, e);
    }
}

在我的演讲者中是以下内容:

public partial class Presenter
{
    Form1 myForm;
    public Presenter()
    {
        myForm = new Form1();
        myForm.ChooseLocationHandler += ChooseLocationHandler;
        myForm.Show();
    }

    public void ChooseLocationHandler(object obj, EventArgs e)
    {
        Form1 sender = (Form1)obj;

        FolderBrowserDialog fbd = new FolderBrowserDialog();
        fbd.RootFolder = System.Environment.SpecialFolder.MyComputer;
        fbd.ShowNewFolderButton = true;
        if (fbd.ShowDialog() == DialogResult.Cancel)
            return;

        sender.DestFolder = fbd.SelectedPath;
    }
}

我在 fbd.ShowDialog() 上遇到异常。

4

7 回答 7

58

线程是 STA 或 MTA,它不能只为一种方法指定,因此该属性必须存在于入口点上。

STAThreadAttributeMSDN

将此属性应用于入口点方法(C# 和 Visual Basic 中的 Main() 方法)。它对其他方法没有影响。

如果从辅助线程调用此代码,您有 3 个选择:

重要说明:在 MTA 线程中运行(如您所见)System.Windows.Forms 代码是不明智的,某些功能,如文件打开对话框(不仅是文件夹)需要 MTA 线程才能工作。

更改辅助线程单元

如果您自己创建线程(并且不使用 MTA 的特殊性),您可以在开始之前更改它的单元:

var t = new Thread(...);
t.SetApartmentState(ApartmentState.STA);

 

为它创建一个线程

如果您不控制线程创建,您可以在临时线程中进行:

string selectedPath;
var t = new Thread((ThreadStart)(() => {
    FolderBrowserDialog fbd = new FolderBrowserDialog();
    fbd.RootFolder = System.Environment.SpecialFolder.MyComputer;
    fbd.ShowNewFolderButton = true;
    if (fbd.ShowDialog() == DialogResult.Cancel)
        return;

    selectedPath = fbd.SelectedPath;
}));

t.SetApartmentState(ApartmentState.STA);
t.Start();
t.Join();
Console.WriteLine(selectedPath);

 

在另一个(STA)线程中调用

如果您的主线程还包含 System.Windows.Forms 代码,您可以在它的消息循环中调用以执行您的代码:

string selectedPath = null;
Form f = // Some other form created on an STA thread;
f.Invoke(((Action)(() => {
    FolderBrowserDialog fbd = new FolderBrowserDialog();
    fbd.RootFolder = System.Environment.SpecialFolder.MyComputer;
    fbd.ShowNewFolderButton = true;
    if (fbd.ShowDialog() == DialogResult.Cancel)
        return;

    selectedPath = fbd.SelectedPath;
})), null);
Console.WriteLine(selectedPath);
于 2011-07-28T14:00:53.470 回答
3

这解决了我的问题。[STAThread] 静态无效 Main()

只是一个额外的问题:为什么微软不能让事情变得简单?他们是否试图让人们感到厌恶来做一些编码?

于 2012-10-26T15:04:09.260 回答
2

如下所示:

using System.Windows.Forms;
namespace fileConverterBaset64
{
    class Program
    {
        [STAThread]
        static void Main(string[] args)

[STAThread]在您的主要方法之前添加命令。就是这样,它会工作。

于 2019-07-23T15:32:08.717 回答
2

我对 ASP.NET MVC 项目有同样的问题。当我将水晶报告导出为某种格式时,它会显示错误。我所做的是替换

这:

            SaveFileDialog browser = new SaveFileDialog();
            string fileName = "";

            browser.Filter = "Pdf|*.pdf|Txt|.txt";

            if (browser.ShowDialog() == DialogResult.OK)
            {
                ExportFormatType formatType = ExportFormatType.NoFormat;
                switch (browser.FilterIndex)
                {
                    case 2:
                        formatType = ExportFormatType.WordForWindows;
                        break;
                    case 1:
                        formatType = ExportFormatType.PortableDocFormat;
                        break;
                }

                fileName = browser.FileName;
                crReportDocument.ExportToDisk(formatType, fileName);

进入:

Thread thread = new Thread((ThreadStart)(() =>
            {
                SaveFileDialog browser = new SaveFileDialog();
                string fileName = "";

                browser.Filter = "Pdf|*.pdf|Txt|.txt";

                if (browser.ShowDialog() == DialogResult.OK)
                {
                    ExportFormatType formatType = ExportFormatType.NoFormat;
                    switch (browser.FilterIndex)
                    {
                        case 2:
                            formatType = ExportFormatType.WordForWindows;
                            break;
                        case 1:
                            formatType = ExportFormatType.PortableDocFormat;
                            break;
                    }

                    fileName = browser.FileName;
                    crReportDocument.ExportToDisk(formatType, fileName);
                }
            }));

            thread.SetApartmentState(ApartmentState.STA);
            thread.Start();
            thread.Join();
于 2020-07-30T20:46:39.697 回答
1

据我所知,STAThread 属性必须在 main 前面。

于 2011-07-28T14:01:24.413 回答
-1

我遇到了同样的问题,我删除了 3 个未使用的 Dll,它已修复...非常感谢!

于 2020-07-11T06:50:51.920 回答
-3

现在,检查参考中的所有 dll 并删除不使用的 dll。

那真是难以置信。我无法想象那些 dll 会导致这个问题。

于 2018-12-21T04:01:21.727 回答