2

FolderBrowserDialog を使用して C# でフォルダーを選択しようとしています。最初はスレッド例外が発生したので、何が間違っていたのかをグーグルで調べて修正しましたが、今は別の問題で立ち往生しています。フォルダがいつ選択されたか知りたいです。

これは私が今持っているものです。

 private void btnWorkingFolder_Click(object sender, EventArgs e)
    {


        var t = new Thread(SelectFolder);
        t.IsBackground = true;
        t.SetApartmentState(ApartmentState.STA);
        t.Start();

    }

    private void SelectFolder()
    {
        FolderBrowserDialog dialog = new FolderBrowserDialog();
        if (dialog.ShowDialog() == DialogResult.OK)
        {
            txtWorkFolder.Text = dialog.SelectedPath;
        }
    }
}

ここでの問題は、同じスレッドにいないため、txtWorkingFolder のテキストを設定できないことです。txtWorkingFolder のスレッドを変更したくないので、私の質問はこれです。DialogResult.OK が設定されたら、新しいスレッドからその値を変更するにはどうすればよいですか?

編集:

これがメインで、btnWorkingFolder は Form1() の一部です。

class sample
{

    static void Main(string[] args)
    {

       Connect2Exchange conn = new Connect2Exchange();

       Application.EnableVisualStyles();
       Application.SetCompatibleTextRenderingDefault(false);

       Application.Run(new Form1());       

    }


}

2番目の編集:

例のコードを試した後、次の例外が発生します。

System.Threading.ThreadStateException was unhandled
  Message=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.
  Source=System.Windows.Forms
  StackTrace:
       at System.Windows.Forms.FolderBrowserDialog.RunDialog(IntPtr hWndOwner)
       at System.Windows.Forms.CommonDialog.ShowDialog(IWin32Window owner)
       at System.Windows.Forms.CommonDialog.ShowDialog()
       at Mail2DB.Form1.btnWorkingFolder_Click(Object sender, EventArgs e) in C:\Users\marthin\documents\visual studio 2010\Projects\Mail2DB\Mail2DB\Form1.cs:line 44
       at System.Windows.Forms.Control.OnClick(EventArgs e)
       at System.Windows.Forms.Button.OnClick(EventArgs e)
       at System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)
       at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
       at System.Windows.Forms.Control.WndProc(Message& m)
       at System.Windows.Forms.ButtonBase.WndProc(Message& m)
       at System.Windows.Forms.Button.WndProc(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
       at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
       at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
       at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32 dwComponentID, Int32 reason, Int32 pvLoopData)
       at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
       at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
       at System.Windows.Forms.Application.Run(Form mainForm)
       at Mail2DB.sample.Main(String[] args) in C:\Users\marthin\documents\visual studio 2010\Projects\Mail2DB\Mail2DB\sample.cs:line 26
       at System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args)
       at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
       at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()
  InnerException: 

助けてくれてありがとう!/マーチン

4

2 に答える 2

4

ここでスレッドを使用することは非常に不適切です。ダイアログは、残りのウィンドウを更新せずに干渉することなく、UI スレッドで実行することができます。

STA とテキスト ボックスを更新する手間はほんの一部です。ダイアログには親ウィンドウがありません。スレッド上で親として機能する他のウィンドウは使用できず、デスクトップ ウィンドウのみが候補になります。ユーザーが別のウィンドウをアクティブにすると、問題が発生します。ダイアログとオーバーラップする可能性があり、ユーザーがダイアログに戻る良い方法はありません。タスクバーボタンはありません。これは、間違ったタイミングでのアイドル クリックによって偶発的に発生することもあります。ユーザーは、ダイアログが実際に表示されていることに気付かずに、ダイアログを見ることさえないかもしれません。

もう 1 つの問題は、ダイアログがウィンドウの残りの部分に対してモーダルとして機能しないことです。これらは有効なままで、ユーザーがユーザー インターフェイスを操作してダイアログを再度開始できるようにします。

次のように機能させるだけです:

private void btnWorkingFolder_Click(object sender, EventArgs e)
{
    using (var dialog = new FolderBrowserDialog()) {
        if (dialog.ShowDialog() == DialogResult.OK)
        {
            txtWorkFolder.Text = dialog.SelectedPath;
        }
    }
}

ダイアログを残りのウィンドウから独立して実行する必要がある場合は、親として機能する「ホスト」ウィンドウを提供する必要があります。これには、Application.Run() を使用してメッセージ ループをポンピングする必要もあります。 また、ユーザーに再度ダイアログを表示させないための対策として、Enabled プロパティを使用します。

于 2011-01-16T16:47:34.140 に答える
4

Invokeを使用して、実行を GUI スレッドに委譲する必要があります。

private void SelectFolder()
{
    FolderBrowserDialog dialog = new FolderBrowserDialog();
    if (dialog.ShowDialog() == DialogResult.OK)
    {
        Action a = () => txtWorkFolder.Text = dialog.SelectedPath;
        this.Invoke(a);
    }
}

また、ここで何を達成しようとしているのかはあまり明確ではありません。バックグラウンド スレッドを使用してファイル ブラウザー ダイアログを作成しても意味がありません。このタスクは、メイン スレッドで適切に実行できますし、実行する必要があります。

バックグラウンド スレッドは、メイン スレッドのブロックを回避するために、非 UI 関連の潜在的に長時間実行されるタスクを実行するために使用されます。

于 2011-01-16T16:18:26.117 に答える