2011-01-16 2 views
1

FolderBrowserDialog를 사용하여 C#에서 폴더를 선택하려고합니다. 처음에는 Thread 예외가 생겼습니다. 그래서 나는 무엇이 잘못되었는지를 알아 보았습니다.하지만 이제는 nother 문제에 머물러 있습니다. 나는 폴더가 선택되었을 때를 알고 싶어한다.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 일단 설정된 새 스레드에서 값을 변경합니까?

EDIT :

이것이 btnWorkingFolder가 Form1에()의 일부가 주이다 :

class sample 
{ 

    static void Main(string[] args) 
    { 

     Connect2Exchange conn = new Connect2Exchange(); 

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

     Application.Run(new Form1());  

    } 


} 

SECOND EDIT :

발생 다음 예외 주어진 예에서 코드를 시도 후 :

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

스레드 사용은 매우입니다. 대화 상자는 나머지 창을 업데이트하지 않고도 UI 스레드에서 간섭없이 실행할 수 있습니다.

STA를 사용하고 텍스트 상자를 업데이트하는 번거 로움은 그 일부에 지나지 않습니다. 훨씬 더 큰 문제가 있습니다. 대화 상자에는 부모 창이 없습니다. 쓰레드에서 부모 역할을 할 수있는 다른 윈도우는 없으며 데스크톱 윈도우 만 후보가됩니다. 문제는 사용자가 다른 창을 활성화 할 때 시작됩니다. 대화 상자가 겹칠 수 있으므로 사용자가 다시 대화 할 수있는 좋은 방법은 없습니다. 작업 표시 줄 단추가 없습니다. 잘못된 시간에 유휴 클릭이 발생해도 우발적으로 발생할 수 있습니다. 사용자는 실제로 대화 상자가 표시된다는 사실을 알지 못하고 대화 상자를 보지 못할 수도 있습니다.

또 다른 문제는 대화 상자가 나머지 Windows와 모달 관계를 유지하지 않는다는 것입니다. 활성화 된 상태로 유지되어 사용자 인터페이스를 조작하고 대화 상자를 시작합니다. .

은 그냥이 같이 작동합니다

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

일반적으로 Program.cs에있는 Main() 메서드에 문제가 있습니다. 하지만 "Mail2DB.sample"과 비슷한 것으로 이동 한 것 같습니다. 일반적으로있는 것처럼 [STAThread] 특성을 가져야합니다. –

+0

@Passant 고맙습니다. 문제가 있습니다.이 프로젝트는 오래된 프로젝트입니다. – Marthin

4

당신은 GUI 스레드에 실행을 위임 할 Invoke을 사용해야합니다

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

은 또한 당신이 여기에 달성하려고하는 것을 매우 분명하지 않다. 백그라운드 스레드를 사용하여 파일 브라우저 대화 상자를 만드는 것은 의미가 없습니다. 이 작업은 주 스레드에서 수행 될 수 있고 잘 수행되어야합니다.

백그라운드 스레드는 주 스레드 차단을 방지하기 위해 잠재적으로 장기 실행되는 작업을 수행하는 데 사용됩니다.

+0

새 스레드의 유일한 이유는 http://msdn.microsoft.com/en-us/library/bb383879(v=vs.90).aspx의 예제를 사용하여 예외가 발생했기 때문입니다. 새로운 스레드에 대한 예제를 제공하는 Stack의 게시물. 비록 도움을 Thx! – Marthin

+0

@Marthin, 새 스레드가 필요하지 않습니다. 양식의 일부 단추에 대한 클릭 콜백에서 이러한 작업을 직접 수행 할 수 있습니다. –

+0

@Marthin : 예외를 트래핑하는 대신 처리되지 않은 예외로 죽을 다른 스레드를 스핀하는 대신? – Tergiver