Исключение при использовании FolderBrowserDialog - PullRequest
21 голосов
/ 28 июля 2011

Я получаю следующее исключение при попытке использовать 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, удалить все dll из папки Debug или использовать метод 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 ]

51 голосов
/ 28 июля 2011

Поток является STA или MTA, его нельзя указать только для одного метода, поэтому атрибут должен присутствовать в точке входа.

С STAThreadAttribute в MSDN :

Примените этот атрибут к методу точки входа (метод Main () в C # и Visual Basic). Это не влияет на другие методы.

Если этот код вызывается из вторичного потока, у вас есть 3 варианта:

ВАЖНОЕ ПРИМЕЧАНИЕ: Выполнение (как вы, кажется, делаете) кода System.Windows.Forms внутри потока MTA неразумно, некоторые функции, такие как диалоги открытия файлов (не только папка), требуют работы потока 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 голос
/ 26 октября 2012

Это исправило мою проблему.[STAThread] static void Main ()

Просто дополнительный вопрос: почему Microsoft не может все упростить?Они пытаются отвращать людей к некоторому кодированию?

1 голос
/ 28 июля 2011

Насколько мне известно, атрибут STAThread должен находиться перед main.

0 голосов
/ 21 декабря 2018

Теперь проверьте все dll в справочнике и удалите dll, не используемые.

Это было невероятно.Я никогда не мог предположить, что эти DLL вызывают эту проблему.

...