2011-01-16 3 views
1

Я пытаюсь использовать FolderBrowserDialog, чтобы выбрать папку на C#. Сначала я получил исключение в Thread, поэтому я искал то, что было неправильно, и исправил это, но теперь я застрял в еще одной проблеме. Я хочу знать, когда была выбрана папка.C# threading a FolderBrowserDialog

Это то, что я получил прямо сейчас.

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

    } 


} 

ВТОРОЙ РЕДАКТИРОВАТЬ:

После попытки код из примеров приведены следующие происходит исключение:

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: 

Thx для любой помощи! /Marthin

ответ

4

Использование темы очень здесь неуместно. Диалог уже вполне способен работать в потоке пользовательского интерфейса без вмешательства без обновлений остальных окон.

Сложность с STA и получение обновленного текстового поля - лишь малая его часть. Проблема гораздо большая, в диалоговом окне нет родительского окна. В потоке нет других окон, чтобы выступать в роли родителя, но только окно рабочего стола является кандидатом. Проблема начинается, когда пользователь активирует другое окно. Он может перекрывать диалог, и пользователю не удастся вернуться к нему. На панели задач нет кнопки. Это также может произойти случайно с незанятого клика в неподходящее время. Пользователь может даже не увидеть диалог, не понимая, что он действительно отображается.

Другая проблема заключается в том, что диалог не будет действовать модально для остальных ваших окон. Они остаются включенными, позволяя пользователю управлять пользовательским интерфейсом и снова запускать диалог .

Просто заставить его работать так:

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.

+0

Я просто попробовал это и получил тот же ThreadException: ThreadStateException был необработанным. Я редактировал свой пост с полным исключением. – Marthin

+2

Что-то не так с вашим методом Main(), который обычно находится в Program.cs. Но, похоже, вы переместили его в нечто похожее на «Mail2DB.sample». Он должен иметь атрибут [STAThread], как обычно. –

+0

@Passant Спасибо, это была проблема, это старый проект, не знаю, почему iv оставил это. – Marthin

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, чтобы избежать блокировки основного потока.

+0

Единственная причина для нового потока - исключение, которое я получил от использования примера на http://msdn.microsoft.com/en-us/library/bb383879(v=vs.90).aspx. Итак, сообщение в Stack дало пример для нового потока. Thx за помощь, хотя! – Marthin

+0

@Marthin, вам не нужна новая тема. Вы можете напрямую выполнять эти задачи в обратном вызове на некоторых кнопках в вашей форме. –

+0

@Marthin: Итак, вместо того, чтобы захватить исключение, вы откручиваете другой поток, который умрет с необработанным исключением? – Tergiver