Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WPF Dispatcher.Invoke 'hanging'

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.

like image 483
Matthew Savage Avatar asked Nov 05 '08 02:11

Matthew Savage


4 Answers

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

like image 127
Ana Betts Avatar answered Nov 11 '22 07:11

Ana Betts


I think this is better shown with code. Consider this scenario:

Thread A does this:

lock (someObject)
{
   // Do one thing.
   someDispatcher.Invoke(() =>
   {
      // Do something else.
   }
}

Thread B does this:

someDispatcher.Invoke(() =>
{
   lock (someObject)
   {
      // Do something.
   }
}

Everything might appear fine and dandy at first glance, but its not. This will produce a deadlock. Dispatchers are like queues for a thread, and when dealing with deadlocks like these its important to think of them that way: "What previous dispatch could have jammed my queue?". Thread A will come in...and dispatch under a lock. But, what if thread B comes in at the point in time at which Thread A is in the code marked "Do one thing"? Well...

  • Thread A has the lock on someObject and is running some code.
  • Thread B now dispatches, and the dispatcher will try to get the lock on someObject, jamming up your dispatcher since Thread A has that lock already.
  • Thread A will then queue up another dispatch item. This item will never be fired, because your dispatcher will never finish processing your previous request; its already jammed up.

You now have a beautiful deadlock.

like image 8
Alexandru Avatar answered Nov 11 '22 05:11

Alexandru


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.

like image 6
Keith Avatar answered Nov 11 '22 07:11

Keith


I think you mean if (!this.Dispatcher.CheckAccess())

I am also geting a hang with Invoke, or if I can BeginInvoke my delegate isn't being called - seem to be doing everything by the book :-(

like image 3
Andrew Avatar answered Nov 11 '22 07:11

Andrew