2011-05-03 3 views
7

내가 겪고있는 문제에 대해 누군가 알릴 수 있습니까?Dispatcher.BeginInvoke()의 동작에 혼란이 있음

저는 wpf 프로젝트에서 작업하고 있습니다. 시나리오는 다음과 같습니다 :

기본 UI 스레드에서 창 (모델 창)을 팝업 한 다음 닫아야합니다. 이러한 작업은 다른 UI 스레드 (사용자가 기본 UI 창을 클릭하지 못하도록)에서 시작됩니다. 그런 다음이 창을 닫습니다. 주 코드가 아래에 표시됩니다. 그리고 그것은 작동합니다.

ShowDialog() 반환하기 전에 가까운 방법을 excuted 얻을 것이라고 알고 (적어도이 UI 스레드 경우, 디스패처없이 코드를 의미합니다), 누구 멀티 스레드 경험이 있습니까?

Window window; 
    private void Button_Click(object sender, RoutedEventArgs e) 
    { 
     Thread thread = new Thread(() => 
      { 


       //create a window and let user work from this thread 

      //code is omitted. 



       //create another window on main UI thread 

       Application.Current.Dispatcher.BeginInvoke(new Action(() => 
       { 
        window = new Window(); 
        window.ShowDialog(); 
       })); 



       //do some work here 

       Thread.Sleep(1000); 

       Application.Current.Dispatcher.BeginInvoke(new Action(() => 
       { 
        //Thread.Sleep(1000); 
        window.Close(); 
       })); 
      }); 

     thread.Start(); 
    } 

감사합니다.

답변

14

그래서,이 코드는 정확히 당신이 원하는 방식으로 작동한다는 말을하고 있지만 당신은 단지 이해하려고 노력하고 방법 (그리고 왜 ) 작동?

다음은 작동 방식입니다. 당신의 작업자 스레드가 계속 실행 : 주 (UI) 스레드의 디스패처 큐의 액션을 큐, 다음 즉시 반환

Application.Current.Dispatcher.BeginInvoke(new Action(() => 
{ 
    window = new Window(); 
    window.ShowDialog(); 
})); 

: 첫째, 스레드가이 코드를 실행합니다.

응용 프로그램이 처음 시작될 때 (일반적으로 Application.xrl 객체를 초기화하는 컴파일러에서 생성 된 코드를 통해 Application.Run을 호출하여 명시 적으로 수행 할 수 있지만) 메시지 루프가 시작되었습니다. 이 (의사, 아주 아주 단순화) :

public class Application { 
    public void Run() { 
     while (!Exited && action = Dispatcher.DequeueAction()) 
      action(); 
    } 
} 

그래서 어떤 시점에서 당신이 작업을 대기열 직후, UI 스레드가있는 액션이 ​​생성 포인트, 그것을 큐 떨어져 당신의 행동을 당기고 실행 주위에 얻을 것이다 창과 그것을 모달로 보여줍니다. 다시

Application.Current.Dispatcher.BeginInvoke(new Action(() => 
{ 
    window.Close(); 
})); 

:

나중에
public class Window { 
    public bool? ShowDialog() { 
     DisableOtherWindowsAndShow(); 
     while (!IsClosed && action = Dispatcher.DequeueAction()) 
      action(); 
     EnableOtherWindowsAndHide(); 
     return DialogResult; 
    } 
} 

, 당신의 작업자 스레드가이 코드를 실행합니다

는 모달 창 이제이 같은 (다시, 아주 단순화를)가는 자신의 메시지 루프를 시작합니다 작업이 UI 스레드의 발송자 대기열에 대기하고 BeginInvoke 호출이 즉시 반환되고 작업자 스레드가 계속 실행됩니다.

조만간 또는 그 후에 UI 스레드의 메시지 루프가 동작을 큐에서 제거하고 실행하여 창을 닫을 것을 지시합니다. 이것은 사용자가 제목 표시 줄의 "X"버튼을 클릭했을 때와 본질적으로 동일한 효과를가집니다. 물론 모달 대화 상자 안에있을 때에도 완벽하게 수행 할 수 있습니다.이로 인해 ShowDialog의 메시지 루프가 끝나기 때문에 (대화 상자가 숨겨지고 다른 창이 다시 활성화되고 ShowDialog가 반환되고 원래 (ShowDialog) 작업이 완료되어 반환되고 컨트롤이 떨어지게 됨) Application.Run의 원래 메시지 루프로 돌아갑니다.

스레드 당 하나의 디스패처 큐가 있고 메시지 루프 당 하나가 아닌입니다. 따라서 "닫기"동작은 "대화 표시"동작과 동일한 대기열로 이동합니다. 이것은 이제 Message-loop 폴링을 수행하는 코드의 다른 부분입니다 (Application.Run 내부의 ShowDialog 대신에 ShowDialog 내부에있는 것). 그러나 루프의 기본 사항은 같습니다.

+0

실제로 어떻게 작동하는지 이해하는 데 도움이되는 설명을 해주셔서 감사합니다! 실제로 showdialog 코드를 살펴 보았지만 ComponentDispatcher.PushModal처럼 이해하기 어려운 것이 있습니다. 나는 그것을 벨로우즈에 게시합니다. 제발 좀 도와 주시겠습니까? – xiaoheixiaojie

3

BeginInvoke은 논 블로킹 방법이다; 디스패처 대기열에 작업을 추가하고 작업이 완료 될 때까지 기다리지 않습니다. 대신 Invoke을 사용해야하며, 이는 디스패처 스레드에서 메서드를 동 기적으로 호출합니다. 내가 제대로 질문을 이해한다면

+0

안녕하세요. 회신 해 주셔서 감사합니다. 이 질문에 대한 대답이 아닌 것 같습니다. 기본 UI에서 창을 사용할 수 없게하는 첫 번째 begininvoke 이후에 일부 작업을 수행해야합니다. Invoke를 사용하면 응용 프로그램이 차단됩니다. 지금은 문제가 발생하지 않습니다. – xiaoheixiaojie

관련 문제