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 のいずれかであり、1 つのメソッドだけに指定することはできないため、エントリ ポイントに属性が存在する必要があります。

STAThreadAttributeMSDNから:

この属性をエントリ ポイント メソッド (C# および Visual Basic の Main() メソッド) に適用します。他のメソッドには影響しません。

このコードがセカンダリ スレッドから呼び出される場合、次の 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);
于 2011-07-28T14:00:53.470 に答える
3

これで問題が解決しました。[STAThread] static void 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 に答える
1

私の知る限り、STAThread 属性は main の前になければなりません。

于 2011-07-28T14:01:24.413 に答える