ApplicationContext and the UI thread

The App

I had this very annoying threading issue which took me ages to finally find the answer to in a dark corner of the .NET API. I have this Windows Forms application which sits in the system tray working away, and you can double-click the icon to open a window showing the application details.

One part of the application asynchronously spawns a child process and the "tray" class receives events, such as process started, died, output received, etc. On these events, the tray's tooltip text is updated (also a balloon tip may be shown) and also changes are made to the available right-click context menu items.

So, to create the tray icon without creating a form, I used a custom ApplicationContext instance as described Mitchel Sellers here. This worked fine, however after a seemingly random length of time, the application would freeze. The right-click menu wouldn't show and if the main form was open, it wouldn't respond or repaint.

UI Thread Deadlock

This looked like a classic UI threading issue. In normal WinForms programs, all interactions with a UI element (textbox/label/etc) have to be made on the UI thread. However, in the case of my tray app, this is all happening within the ApplicationContext class, which doesn't have the usual InvokeRequired/BeginInvoke methods. So I was calling the InvokeRequired/BeginInvoke methods on the tray's context menu I'd created within the ApplicationContext class.

These callbacks were all doing the InvokeRequired check, so I spent a good while on a wild goose chase looking at other areas of the application where I was locking, or should be locking fearing a deadlock was happening somewhere else which was causing the freeze.

Then I decided to add copious amounts of logging to try and find the area of code just before the freeze. At this point it became immediately obvious. From the logging, I could see that the callbacks weren't being marshalled back to the main UI thread - the thread that they were created on. During my search for the answer, other people solved this by using the MainForm property of the ApplicationContext instance - however, in my case there isn't a main form instance, so I couldn't use this.

SynchronizationContext to the Rescue

I finally found one random forum with a user posting the same problem and answered by himself with:

I found my solution, all I needed was SynchronizationContext.

Thank You! So I go in search of said class and it turns out to be very easy to fix my app:

private readonly SynchronizationContext syncContext;
public MyApplicationContext() {
  syncContext = new WindowsFormsSynchronizationContext();
}
private void BeginInvoke(Delegate callback, object[] args) {
  syncContext.Post(state => callback.DynamicInvoke((object[])state), args);
}

Problem solved. Instead of using the context menu control to marshal onto the UI thread, which doesn't work in the case, switch the code to use this new BeginInvoke method using the SynchronizationContext. Finally no more app hangs.


Comments:

Commands are a cool feature of both WPF and Silverlight, which allow you bind the Command prrtoepy of an element that derives from ButtonBase (such as a button, menu item or hyperlink button) to a prrtoepy on the view-model which is of type ICommand. Typically, you would use a helper class (called DelegateCommand in my toolkit) to wire up the prrtoepy to a method in the view-model. Commands will automatically enable and disable the button whenever the value of CanExecute changes.I think commands are implemented better in WPF than in Silverlight. WPF has a command manager that will call RaiseCanExecuteChanged at the right times, but in Silverlight you need to call it manually whenever you want the CanExecute invoked. Aside from that, an inherent limitation of commands is that they only work on the Click event of a ButtonBase-derived element, which is pretty limiting. (You can get around this with something like an event-to-command behavior.) But the thing I like least about commands is that they require a lot of extra code in the view-model to support them, when all you really need is a method.Enter event triggers from the Blend SDK. These allow you to write XAML that handles any event on any element, not just a button click. All you have to do is specify a method name for the CallMethodAction you use with the event trigger. No extra code needed in the view-model.However, there is a limitation here, which is that the method cannot have any parameters. That means the method would need to use properties in the view-model. Most of the time, this works fine, because elements in the view are bound to view-model properties. However, there may be cases where it makes more sense to pass a parameter to the method in the view-model (for example, where you wish to navigate to a page and need to pass a relative uri). This is where it makes sense to use a command.So I favor using event triggers / actions most of the time, and using commands when you need to pass a parameter. There is a generic version of DelegateCommand in my that accepts a strongly typed parameter. You can see it in action in the Navigation example that's part of the . You can also check out the online for DelegateCommand. Cheers,Tony

Guy .. Beautiful .. Superb .. I will bookmark your web site and take the feeds additionallyI'm glad to find a lot of useful information here in the submit, we'd like work out extra strategies on this regard, thanks for sharing. . . . . .

Blockquote Instead of using the context menu control to marshal onto the UI thread, which doesn't work in the case, switch the code to use this new BeginInvoke method using the SynchronizationContext. Blockquote

What do you want to say with this? There is no sample code, you only add some words with no information.


Comment Guidelines
See the FAQ for details on the full rules and guidelines. No Spam. Write clearly and thoughtfully - no bad language.