views:

5178

answers:

3

I have a somewhat complex WPF application which seems to be 'hanging' or getting stuck in a Wait call when trying to use the dispatcher to invoke a call on the UI thread.

The general process is:

  1. Handle the click event on a button
  2. Create a new thread (STA) which: creates a new instance of the presenter and UI, then calls the method Disconnect
  3. Disconnect then sets a property on the UI called Name
  4. The setter for Name then uses the following code to set the property:

    if(this.Dispatcher.Thread != Thread.CurrentThread)
    {
        this.Dispatcher.Invoke(DispatcherPriority.Normal, (ThreadStart)delegate{
            this.Name = value; // Call same setter, but on the UI thread
        });
        return;
    }

    SetValue(nameProperty, value); // I have also tried a member variable and setting the textbox.text property directly.

My problem is that when the dispatcher invoke method is called it seems to hang every single time, and the callstack indicates that its in a sleep, wait or join within the Invoke implementation.

So, is there something I am doing wrong which I am missing, obvious or not, or is there a better way of calling across to the UI thread to set this property (and others)?

Edit: The solution was to call System.Windows.Threading.Dispatcher.Run() at the end of the thread delegate (e.g. where the work was being performed) - Thanks to all who helped.

+6  A: 

Invoke is synchronous - you want Dispatcher.BeginInvoke. Also, I believe your code sample should move the "SetValue" inside an "else" statement.

Paul Betts
+1  A: 

This sounds like a deadlock; this would typically happen if the thread calling .Invoke already held a lock / mutex / etc which the UI thread needs to complete it's work. The simplest approach would be to use BeginInvoke instead: that way, the current thread can keep running, and will (presumably) release the lock shortly - allowing the UI to aquire it. Alternatively, if you can identify the offending lock, you could deliberately release it for a duration.

Marc Gravell
Thanks Marc, This explanation is good, however I'm still left clueless as to why there is a lock in the first place. As suggested by yourself and Paul BeginInvoke was an option but not optimal, there is no guarantee of it completing. Crazy strange bugs....
Matthew Savage
+3  A: 

You say you are creating a new STA thread, is the dispatcher on this new thread running?

I'm getting from "this.Dispatcher.Thread != Thread.CurrentThread" that you expect it to be a different dispatcher. Make sure that its running otherwise it wont process its queue.

Keith
Keith, This is a good point. I'm not familiar enough with the dispatcher, but wouldn't the window's dispatcher already be started? The STA Thread is used to create the new window, however if I need to start the dispatcher manually it would explain why it isn't processing...
Matthew Savage
If creating the STA yourself try calling Dispatcher.Run() after you show your window. My understanding is the dispatcher is a message pump and if creating a new UI thread it’ll have a dispatcher create when requested, if you managing the creation you’d have to call Run on the dispatcher.
Keith
Have a look at this post: http://eprystupa.wordpress.com/2008/07/28/running-wpf-application-with-multiple-ui-threads/
Keith