2009-07-31 5 views
1

하나의 버튼이있는 창이 있습니다.이상한 Dispatcher 동작을 설명하십시오 (숨겨진 WPF 기능)

코드 숨김은

private void Button_Click(object sender, RoutedEventArgs e) 
{ 
    Trace.TraceInformation("Button ThreadId: {0}", Thread.CurrentThread.ManagedThreadId); 

    Thread w = new Thread((ThreadStart) Worker); 
    w.SetApartmentState(ApartmentState.STA); // removing/adding this doesn't make effect 
    w.Start(); 
    MessageBox.Show("Direct"); 
} 

void Worker() 
{ 
    Trace.TraceInformation("Worker ThreadId: {0}", Thread.CurrentThread.ManagedThreadId); 

    this.Dispatcher.Invoke((Action)delegate 
           { 
            Trace.TraceInformation("Invoked ThreadId: {0}", Thread.CurrentThread.ManagedThreadId); 
            MessageBox.Show("Invoked"); 
           }); 
} 

2 메시지 상자에 버튼 결과를 클릭합니다. 동시에

는 추적 버튼을 ThreadId 및 호출이을 ThreadId을 위해 같은 번호를 보여줍니다.

+0

그러면 작업자가 주 스레드에서 실행 중입니까? 이 호출을 확인하기 위해 ThisDispatcher.CheckAccess()를 점검하십시오. –

+0

이 예제는 인공적입니다. 나는 오해를 잡기 위해 그것을 만들었습니다. –

+0

MessageBox.Show()는 차단 호출입니다. 즉, "직접"메시지 상자를 클릭하기 전에 Button_Click이 종료되지 않습니다. 각 메시지 상자 앞뒤에 Trace.TraceInformation()을 배치하여 실험했습니다. –

답변

2

Dispatcher는 항상 GUI 스레드에서 작업을 수행합니다. 이것이 당신의 ThreadId가 일치하는 이유입니다. GUI 스레드 - "당신의 ThreadId는 무엇입니까?" Dispatcher를 통해 일부 작업을 수행하면 GUI 스레드로 다시 이동합니다.

0

전 완전히 틀렸어도이 WPF Dispatcher에 대한 내용이 너무 슬프지만 저번으로 에 전화하는 것처럼 보입니다 .Dispatcher은 Window (UI 스레드) Dispatcher입니다. 따라서 모든 코드는 UI 스레드에서 실행되며 응용 프로그램 인스턴스화 된 스레드에서는 실행되지 않습니다. 여기

[편집]

제가

DispatcherQuestion.vshost.exe Information: 0 : Button ThreadId: 9 // UI Thread 
DispatcherQuestion.vshost.exe Information: 0 : Worker ThreadId: 11 // Thread w 
DispatcherQuestion.vshost.exe Information: 0 : Invoked ThreadId: 9 // UI Thread 

9 ThreadID 상기 코드를 실행로부터 콘솔 출력되는 사용자 인터페이스 스레드이다. UI 스레드에 의해 Button과 Invoke 호출이 모두 설계된대로 수행됩니다.

MSDN에서 this article today이 발견되어 WPF 스레딩/디스패처 모델에 대한 내용이 명확하게 정리되었습니다.

+0

이 경우 ManagedThreadId가 일치하는 이유는 무엇입니까? –

+0

ManagedThreadId에 대한 첫 번째 호출과 마지막 호출이 일치해야합니다. –

+1

그가 이것을 말한 것은 중요하지 않습니다. 디스패처. 그는 Button Dispatcher 나 다른 Control 's Dispatcher를 사용할 수있었습니다. Dispatcher는 항상 UI 스레드에서 실행됩니다. – Charlie

1

산책 후 나는 무슨 일이 일어 났는지 이해했다.

여기 내 설명 아이디어 (문제가 게시 된 이유 또는 코드)가 잘못되었습니다.

Button_ClickDispatcher 스레드에서 실행됩니다. 내가 알고있는 것처럼 Dispatcher 스레드는 윈도우와 그 자식을위한 하나의 스레드입니다.

Button_Click이 1 초 이상 걸리고 사용자가 버튼을 다시 클릭하거나 UI와 상호 작용하는 경우에도 다음 Button_Click (또는 다른 적절한 핸들러)은 즉시 실행되지 않고 배치됩니다. 대기열에 있습니다.

Dispatcher.Invoke은 UI 스레드에서 대리인을 실행합니다. Invoke, 나는 대리자 GetMessage() 루프에 메시지를 보내고 메시지가 완료 될 때까지 호출 스레드를 차단합니다.

Button_Click 종료 후에 만 ​​실행을 시작합니다.

MessageBox.Show()은 차단 호출입니다. 사용자가 '확인'을 클릭하기 전에 다음 명령문이 실행되지 않습니다.

사실 실제로 Dispatcher는 서로 다른 창을 구별하고 Button_Click이 모달 대화 상자를 호출 했으므로 창과의 모든 상호 작용에서 경고음이 발생하고 메시지 상자가 깜박 거리는 것을 알고 있습니다.

그러나 메시지를 전달합니다. 결국 모든 사용자 클릭이 Button.Click 메시지로 변환되고 메시지 상자가 닫히는 이유입니다.

이렇게 호출 된 대리자는 전에Button_Click이 종료되기 전에 실행됩니다. 호출 된 대리자 Button_Click으로 나뉩니다.

P. 코드에서 알 수 있듯이 대리인은 MessageBox.Show()이라고도합니다. 이로 인해 새 메시지 상자 이 이전 버전의 모달에 이르게됩니다. "호출 된"메시지 상자 앞에 "직접"msgBox에서 '확인'을 클릭 할 수 없다는 점에 유의했습니다.

+1

정렬 방법. 너는 가깝다. 이 기사를 매우주의 깊게 읽으십시오. 알아 내려고 실험하려는 모든 것을 설명합니다. http://msdn.microsoft.com/en-us/library/ms741870.aspx –

+0

빙고! 이 기능을 '중첩 루프'라고합니다. 고맙습니다! –

+0

문제 없습니다. 행운을 빕니다. –

관련 문제