tags:

views:

427

answers:

3

I have a window with a single button within.

The code-behind is

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");
                               });
}

Clicking the button results in 2 message boxes.

At the same time, trace shows same numbers for Button ThreadId and Invoked ThreadId.

+2  A: 

The Dispatcher always carries out work on the GUI thread. That is why your ThreadId's match up. You are asking the GUI thread- "what's your ThreadId?" and then performing some work through the Dispatcher, which is again going to the GUI thread.

Charlie
A: 

I'm new to this WPF Dispatcher stuff so downvote me if I am totally wrong, but it looks like your call to this.Dispatcher is really your Window's (UI thread) Dispatcher. Thus, any code will be executed by the UI thread, not your application instantiated thread.

[Edit]

Here is the console output I received from running the above code

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 is the user interface thread. Your Button and your Invoke call are both being performed, as designed, by the UI thread.

I found this article today on MSDN that really clarified things about the WPF Threading/Dispatcher model.

Matthew Ruston
In this case, why do ManagedThreadId match ?
modosansreves
The first and last calls to ManagedThreadId are supposed to match.
Matthew Ruston
It doesn't matter that he said this.Dispatcher. He could have used the Button Dispatcher or any other Control's Dispatcher. The Dispatcher executes on the UI thread- always.
Charlie
A: 

After taking a walk I understood what was happening.

Here is my explanation idea what's wrong with the code (or the reason the question was posted).

Button_Click is executed in the Dispatcher thread. The Dispatcher thread, as I know, is a single one for a window and its children.

Even if Button_Click takes more than a second (long enough), and user manages to click the button again (or somehow else interact with UI), the next Button_Click (or other appropriate handler) is not executed immediately, but placed in the dispatching queue.

Dispatcher.Invoke executes a delegate in the UI thread. Invoke, I suppose, sends a message to the delegate GetMessage() loop and blocks the calling thread till the message completes.

I expected the delegate to begin execution only after Button_Click exits.

MessageBox.Show() is a blocking call. Next statement won't be executed before the user clicks 'Ok'.

What is actually happening is the Dispatcher actually distinguishes between different windows and knows that Button_Click has called a modal dialog and therefore any interaction with the window should produce a beep and the message box should flash.

But is goes on dispatching messages. After all, this why all user clicks are translated into Button.Click messages and the message box gets closed.

This is why the invoked delegate is executed before Button_Click exits. The invoked delegate breaks into the Button_Click.

P.S. As you see in the code, the delegate also calls MessageBox.Show(). This leads to a new message box which is modal to the previous one. I noted I cannot click 'Ok' on the "Direct" msgBox before "Invoked" one.

modosansreves
Sort of. You are close. Read this article very carefully. It explains most everything you are trying to experiment to figure out. http://msdn.microsoft.com/en-us/library/ms741870.aspx
Anderson Imes
Bingo! The feature is called 'nested loops'. Thank you!
modosansreves
No problem. Good luck.
Anderson Imes