2009-07-31 10 views
1

私は1つのボタンがあるウィンドウを持っています。奇妙なディスパッチャの動作を説明します(非表示の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"); 
           }); 
} 

あります。

同時に、トレースはボタンに同じ数字が呼び出されますがをスレッドIDスレッドIDを示しています。

+0

次に、ワーカーはメインスレッドで実行していますか? thisDispatcher.CheckAccess()をチェックして、呼び出しが必要であったかどうかを確認します。 –

+0

この例は人工的です。私はおそらく私の誤解をキャッチするためにそれを作成しました。 –

+0

MessageBox.Show()はブロッキング呼び出しです。つまり、「Direct」メッセージボックスをクリックする前にButton_Clickは終了しません。私は各メッセージボックスの前後にTrace.TraceInformation()を配置して実験しました。 –

答えて

2

Dispatcherは、常にGUIスレッドで作業を実行します。そういうわけで、あなたのThreadIdがマッチアップしているのです。あなたはGUIスレッドに「あなたのThreadIdは何ですか?」と尋ねています。次にDispatcherを介していくつかの作業を行います。これはGUIスレッドに再び行きます。

0

私は完全に間違っていますが、へのあなたの呼び出しのように見えます.Dispatcherは本当にあなたのウィンドウ(UIスレッド)ディスパッチャーです。したがって、アプリケーションスレッドのインスタンスではなく、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 

のThreadID 9上記のコードを実行してから受信コンソール出力されるユーザインタフェーススレッドです。あなたのButtonとInvokeの呼び出しは、設計どおりにUIスレッドによって実行されています。

MSDNでthis article todayが見つかりました。これは、WPFスレッディング/ディスパッチャーモデルについて実際に明らかにしました。

+0

この場合、ManagedThreadIdはなぜ一致しますか? –

+0

ManagedThreadIdの最初と最後の呼び出しは一致するはずです。 –

+1

彼がこれを言ったことは問題ではない。ディスパッチャー。彼はButton Dispatcherや他のControlのDispatcherを使用していた可能性があります。ディスパッチャはUIスレッドで常に実行されます。 – Charlie

1

散歩をした後、私は何が起こっているのか理解しました。

ここに私の の説明 アイデアコード(または質問が投稿された理由)の問題です。

Button_Clickは、Dispatcherスレッドで実行されます。私が知っている通り、Dispatcherスレッドは、ウィンドウとその子のためのスレッドです。

Button_Clickが1秒以上かかっていても、ユーザーがボタンをもう一度クリックしたり、UIとやりとりしたりすると、次のButton_Click(または他の適切なハンドラ)はすぐに実行されず、 ディスパッチキューにあります。

Dispatcher.Invokeは、UIスレッドでデリゲートを実行します。 Invoke、私は、デリゲートGetMessage()ループにメッセージを送信し、メッセージが完了するまで呼び出しスレッドをブロックすると思います。

は、デリゲートがButton_Click終了後にのみ実行を開始すると予想しました。

MessageBox.Show()はブロッキングコールです。次のステートメントは、ユーザーが「OK」をクリックする前に実行されません。

Dispatcherは実際には異なるウィンドウを区別し、Button_Clickがモーダルダイアログを呼び出したことを知っているため、ウィンドウとのやり取りによってビープ音が鳴り、メッセージボックスが点滅するはずです。

しかし、は、ディスパッチメッセージになります。結局のところ、すべてのユーザーのクリックがButton.Clickメッセージに変換され、メッセージボックスが閉じられる理由です。

Button_Clickが終了する前に、呼び出されたデリゲートが実行されるのはこのためです。 呼び出されたデリゲートButton_Clickに分割されます。

P.S.コードでわかるように、代理人はMessageBox.Show()も呼び出します。これにより、新しいメッセージボックスが得られます。このメッセージボックスは、前のメッセージボックスのになります。私は、 "呼び出し"前に "直接" msgBox上で "OK"をクリックできないことに注意しました。

+1

並べ替えあなたは近くにいる。この記事をよく読んでください。それはあなたが把握するために実験しようとしているほとんどすべてを説明します。 http://msdn.microsoft.com/en-us/library/ms741870.aspx –

+0

ビンゴ!この機能は「ネストループ」と呼ばれます。ありがとうございました! –

+0

問題ありません。がんばろう。 –

関連する問題