web-dev-qa-db-ja.com

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()で例外が発生します。

22
Daniel

スレッドはSTAまたはMTAのいずれかであり、1つのメソッドに対してのみ指定することはできないため、属性はエントリポイントに存在する必要があります。

From STAThreadAttribute in MSDN

この属性をエントリポイントメソッド(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);
52

これで問題が解決しました。 [STAThread] static void Main()

余計な質問ですが、なぜマイクロソフトは物事をシンプルにできないのですか?彼らは人々にいくつかのコーディングを嫌悪させようとしていますか?

3
Eric Mariacher

以下のように簡単です:

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

Mainメソッドの前に[STAThread]コマンドを追加します。それだけです、うまくいきます。

1
Shankar K Arun

STAThread属性は、私が知る限り、メインの前にある必要があります。

1
Mario The Spoon

ここで、リファレンスのすべてのDLLを確認し、使用していないDLLを削除します。

それは信じられないことでした。これらのDLLがこの問題を引き起こしているとは想像もできませんでした。

0
user10590035