2011-11-06 2 views
0

다음 코드로 새 스레드에서 새 창을 열 수 있습니다.새 스레드에서 열리는 새 창에서 텍스트 상자를 업데이트하는 방법은 무엇입니까?

다음 코드는 MainWindow.xaml.cs를

private void buttonStartStop_Click(object sender, RoutedEventArgs e) 
{  

    Test test = new Test(); 

    Thread newWindowThread = new Thread(new ThreadStart(test.start)); 
    newWindowThread.SetApartmentState(ApartmentState.STA); 
    newWindowThread.IsBackground = true; 
    newWindowThread.Start(); 
} 

에서하고 test.start()

public void start() 
{ 

    OutputWindow outputwindow = new OutputWindow(); 
    outputwindow.Show(); 


    Output.print("Begin"); 
    System.Windows.Threading.Dispatcher.Run(); 
    Output.print("FINAL"); 
    System.Windows.Threading.Dispatcher.Run(); 

} 

에서 다음 그리고 다음은 출력 클래스에서입니다

public static void print(String str) 
{ 
    Dispatcher uiDispatcher = OutputWindow.myOutputWindow.Dispatcher; 
    uiDispatcher.BeginInvoke(new Action(delegate() { OutputWindow.myOutputWindow.textBoxOutput.AppendText(str + "\n"); })); 
    uiDispatcher.BeginInvoke(new Action(delegate() { OutputWindow.myOutputWindow.textBoxOutput.ScrollToLine(OutputWindow.myOutputWindow.textBoxOutput.LineCount - 1); })); 
} 

public static void printOnSameLine(String str) 
{ 
    Dispatcher uiDispatcher = OutputWindow.myOutputWindow.Dispatcher; 
    uiDispatcher.BeginInvoke(new Action(delegate() { OutputWindow.myOutputWindow.textBoxOutput.AppendText(str); })); 
    uiDispatcher.BeginInvoke(new Action(delegate() { OutputWindow.myOutputWindow.textBoxOutput.ScrollToLine(OutputWindow.myOutputWindow.textBoxOutput.LineCount - 1); })); 
} 

"Begin"텍스트 상자에 인쇄되지만 "FINAL"은 표시되지 않습니다. Test 클래스의 start 메소드를 upda로 설정합니다. 프로그램을 통해 outputwindow의 텍스트 상자를 봅니다. 이 작업을 수행하는 가장 좋은 방법은 무엇입니까?

미리 감사드립니다.

답변

0

나는 무엇을 하려는지 잘 모르겠습니다. System.Windows.Threading.Dispatcher.Run()을 호출하여 FINAL이 인쇄되지 않는 것이 정상입니다. 이 메서드는 스레드를 활성 상태로 유지하고 이벤트를 수신합니다. Run 메소드 내부에 while (true) {}가있는 것처럼 이것을 볼 수 있습니다. 메소드는 Dispatcher가 종료 될 때까지 계속 실행됩니다. 백그라운드 스레드를 활성 상태로 유지하고 메시지를 설정해야 할 때 다른 스레드에서 정적 메서드를 호출해야합니다.

 // reference to window in another thread 
     Window outputWindow = null; 

     Thread thread = new Thread(() => 
     { 
      // another thread 
      outputWindow = new Window(); 
      outputWindow.Show(); 
      // run event loop 
      System.Windows.Threading.Dispatcher.Run(); 
     }) { ApartmentState = ApartmentState.STA, IsBackground = true }; 
     thread.Start(); 

     while (outputWindow == null) 
     { 
      // wait until the window in another thread has been created 
      Thread.Sleep(100); 
     } 

     // simulate process 
     for (int i = 0; i < 10; i++) 
     { 
      outputWindow.Dispatcher.BeginInvoke((Action)(() => { outputWindow.Title = i.ToString(); }), System.Windows.Threading.DispatcherPriority.Normal); 
      Thread.Sleep(500); // simulate some hard work so we can see the change on another window's title 
     } 

     // close the window or shutdown dispatcher or abort the thread... 
     thread.Abort(); 

편집 :

이 빠른 & 더러운 일반적인 해결책이 될 수 있습니다 다음은 예입니다. DoSomeHardWork는 진행 정보를 표시하는 대기 창을위한 또 다른 GUI 스레드를 생성합니다. 이 창은 실제로 작업을 수행하는 작업 스레드를 만듭니다. 작업은 메소드 Action에서 구현됩니다. 첫 번째 인수는 대기 창이므로 작업 스레드에서 변경할 수 있습니다. 물론 현실 세계에서는 윈도우 구현이 아닌 인터페이스를 거쳐야합니다. 그러나 이는 단지 예일뿐입니다. 두 번째 인수는 객체이므로 필요한 모든 것을 작업 스레드에 전달할 수 있습니다. 더 많은 인수가 필요하면 object []를 전달하거나 메소드 서명을 수정하십시오. 이 예에서는 카운터와 수면을 통한 노력을 시뮬레이션합니다. 버튼을 여러 번 클릭하면이 코드를 실행할 수 있으며, 모든 대기 윈도우가 동결없이 자신의 카운터를 세는 것을 볼 수 있습니다. 다음은 코드입니다.

public static void DoSomeHardWork(Action<Window, object> toDo, object actionParams) 
    { 
     Thread windowThread = new Thread(() => 
     { 
      Window waitWindow = new Window(); 
      waitWindow.Loaded += (s, e) => 
      { 
       Thread workThread = new Thread(() => 
       { 
        // Run work method in work thread passing the 
        // wait window as parameter 
        toDo(waitWindow, actionParams); 
       }) { IsBackground = true }; 
       // Start the work thread. 
       workThread.Start(); 
      }; 
      waitWindow.Show(); 
      Dispatcher.Run(); 
     }) { ApartmentState = ApartmentState.STA, IsBackground = true }; 
     // Start the wait window thread. 
     // When window loads, it will create work thread and start it. 
     windowThread.Start(); 
    } 

    private void MyWork(Window waitWindow, object parameters) 
    { 
     for (int i = 0; i < 10; i++) 
     { 
      // Report progress to user through wait window. 
      waitWindow.Dispatcher.BeginInvoke((Action)(() => waitWindow.Title = string.Format("{0}: {1}", parameters, i)), DispatcherPriority.Normal); 
      // Simulate long work. 
      Thread.Sleep(500); 
     } 
     // The work is done. Shutdown the wait window dispather. 
     // This will stop listening for events and will eventualy terminate 
     // the wait window thread. 
     waitWindow.Dispatcher.InvokeShutdown(); 
    } 

    private void button1_Click(object sender, RoutedEventArgs e) 
    { 
     DoSomeHardWork(MyWork, DateTime.Now); 
    } 
+0

답장과 코드를 보내 주셔서 감사합니다. 이것은 내가하려고하는 것입니다 : 1. buttonStartStop을 클릭하면 다른 클래스의 메서드가 시작되어 다른 스레드에서 실행되기를 원합니다. 2. "시작"방법은 텍스트 상자가 포함 된 새 창을 열며 작동하면서 사용자 의견을 제공하기 위해 텍스트 상자를 업데이트합니다. – Arya

+0

먼저 텍스트 상자 양식을 작성한 다음 새 양식이 스레드를 작성하여 시작할 수 있습니다. 최소한 sleep() 루프 하나를 제거합니다. –

+0

이 경우에는 현재 GUI 스레드에서 창을 열고 백그라운드 스레드에서 다른 모든 작업을 수행합니다. 열린 창에서의 업데이트는 GUI 디스패처를 통해 직접 이동할 수 있습니다. 어떻게 구성 할 것인가는 중요하지 않습니다. 다음을 고려하십시오. 1. 백그라운드 스레드에서 창을 작성한 경우 스레드를 STA로 설정하고 Show() 다음에 Dispatcher.Run()을 호출해야합니다. 2.열린 창에 대한 모든 호출은 Dispatcher 객체를 통과해야합니다. 3. "진행 정보"창이 처리를 실행하는 동일한 스레드에 있지 않아야합니다. 그렇지 않으면 처리가 차단됩니다. 몇 가지 코드가 필요하면 ... 저에게 의견을 말하십시오. – user1018735

0

UI 요소를 만드는 스레드 (UI 스레드)가 요소를 소유하고있는 것이 이상적입니다. Dispatcher를 사용하면 비 UI 관련 처리를 백그라운드 스레드로 푸시하는 것이 전부입니다. 백그라운드 프로세스가 완료되면 결과가 다시 기본 UI 스레드로 푸시됩니다. 샘플보기는 다음을 참조하십시오 : http://weblogs.asp.net/pawanmishra/archive/2010/06/06/understanding-dispatcher-in-wpf.aspx

관련 문제