Monday, April 26, 2010

Quick way to cross thread invoke

In windows forms, everything is still single threaded. If you've ever tried to use multiple threads and various controls (form timers for example - the non thread safe kind) you will realize properties start disappearing because they all use TLS (Thread Local Storage) which of course - is thread specific. You must set properties and call events on the thread that created the control. You can cross post messages into another app's message queue (which interestingly enough was the source of the 'shatter' attack some years ago allowing attacking applications to take control of other apps by malformed wm_timer message) without a problem but that's a bit more rare now in managed code than it was in native code days.

If you need to set a property or call a method on a control from a worker thread in you needed to create a delegate. The syntax was sometimes a pain.

To easily call this without a 'outside' (ie in class declarations as was typical) setup of the delegates
simply call it directly by creating a delegate inline using an anonymous method or lambda expression. Either one works - it's your preference on syntax:

yourControl.Invoke((MethodInvoker)delegate() { yourControl.Value=0; });


yourControl.Invoke((Action) ( () => yourControl.Value=0));

What does this save?
1. You don't have to create a separate method.
2. You don't have to declare a separate delegate.

So let's say you wanted to increase the count on a progess bar from a worker thread, you could simply do (off the top of my head.. I believe the invoke needs to be called on the container StatusStrip control) :

statusBar.Invoke((MethodInvoker)delegate() { progressBar.Increment(1); });

Hope this helps - I use it quite frequently. Of course, please don't sprinkle the same line all over your code, wrap it in a method call in case you need to change it.

1 comment:

  1. This comment has been removed by a blog administrator.