web-dev-qa-db-fra.com

Exception lors de l'utilisation de FolderBrowserDialog

L'exception suivante s'affiche lorsque j'essaie d'utiliser 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.

J'ai largement cherché ce problème dans Google et les solutions suggérées par tous semblent être de mettre [STAThreadAttribute] au-dessus de la méthode Main, de supprimer toutes les dll du dossier Debug ou d'utiliser la méthode Invoke. J'ai essayé toutes ces solutions et j'obtiens toujours la même exception.

Voici le code:

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

Et dans mon présentateur est la suivante:

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;
    }
}

Je reçois l'exception sur fbd.ShowDialog ().

20
Daniel

Un thread est soit STA soit MTA, il ne peut pas être spécifié pour une seule méthode, donc l'attribut doit être présent sur le point d'entrée.

De STAThreadAttribute dans MSDN :

Appliquez cet attribut à la méthode du point d'entrée (la méthode Main () dans C # et Visual Basic). Cela n'a aucun effet sur les autres méthodes.

Si ce code est appelé depuis un thread secondaire, vous avez 3 choix:

REMARQUE IMPORTANTE: Exécuter (comme vous semblez le faire) du code System.Windows.Forms dans un thread MTA n'est pas sage, certaines fonctionnalités telles que les boîtes de dialogue d'ouverture de fichier (et pas uniquement les dossiers) nécessitent un thread MTA pour fonctionner.

Changer votre appartement de fil secondaire

Si vous créez le fil vous-même (et n'utilisez pas la spécificité de MTA), vous pouvez simplement changer d'appartement avant de le démarrer:

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

Créer un fil juste pour ça

Si vous ne contrôlez pas la création du thread, vous pouvez le faire dans un thread temporaire:

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

Invocation dans un autre thread (STA)

Si votre thread principal contient également du code System.Windows.Forms, vous pouvez l'invoquer dans sa boucle de message pour exécuter votre code:

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);
49
Julien Roncaglia

L'attribut STAThread doit être en face de main pour autant que je sache.

1
Mario The Spoon

Cela a résolu mon problème. [STAThread] Static void Main ()

Juste une question supplémentaire: pourquoi Microsoft ne peut-il pas simplifier les choses? Est-ce qu'ils essaient de dégoûter les gens de coder?

0
Eric Mariacher

Maintenant, vérifiez toutes les dll dans la référence et supprimez dll ne pas utiliser.

C'était incroyable. Je n'aurais jamais pu imaginer que ces DLL causent ce problème.

0
user10590035