使用FolderBrowserDialog时出现异常

时间:2011-07-28 13:57:42

标签: c# multithreading exception folderbrowserdialog

尝试使用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()上获得了Exception。

7 个答案:

答案 0 :(得分:51)

线程是STA或MTA,不能仅为一个方法指定,因此该属性必须出现在入口点上。

来自STAThreadAttribute in MSDN

  

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

如果从辅助线程调用此代码,您有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);

答案 1 :(得分:1)

据我所知,STAThread属性必须位于main之前。

答案 2 :(得分:1)

这解决了我的问题。     [STAThread]     static void Main()

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

答案 3 :(得分:0)

简单如下:

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

在主要方法之前添加命令[STAThread]。就是这样,它将起作用。

答案 4 :(得分:0)

我也遇到了同样的问题,我删除了3个未使用的Dll's,并修复了...谢谢了!

答案 5 :(得分:0)

我在ASP.NET MVC项目中遇到了同样的问题。当我将Crystal报表导出为某种格式时,它会向我显示错误。我所做的是替换

            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();

答案 6 :(得分:-1)

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

这太不可思议了。我真没想到那些dll会导致此问题。