C # продвигает FolderBrowserDialog - PullRequest
1 голос
/ 16 января 2011

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

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

 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: 

Спасибо за любую помощь!/ Marthin

Ответы [ 2 ]

4 голосов
/ 16 января 2011

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

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

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

Просто сделайте так:

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

Если вам действительно действительно нужно, чтобы диалоговое окно запускалось независимо от остальных окон, вам нужно предоставить окно 'host', которое может выступать в роли родителя. Теперь это также требует от вас прокачки цикла сообщений с помощью Application.Run (). И противодействует тому, чтобы пользователь снова вызывал диалог, используйте свойство Enabled.

4 голосов
/ 16 января 2011

Вы должны использовать Invoke , чтобы делегировать выполнение потоку GUI:

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

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

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

...