Wednesday, October 19, 2005

Making GUI Thread Programming in C# easier - take 2

(Update 2: I've had several iterations with John on his blog post . First, I wish to thank him for his help and the time he's taken to answer my questions. It turns out I was mostly wrong. I always thought (God knows why) that the UI may be created by several threads and that there is no guarantee that a form and its child controls would all be created on the same thread. I was wrong, and there lay the root of what I thought was missing in the SafeInvokeHelper. For all the details of our discussion, I suggest you take a look at the original post and its comments.)

(Updated following John's remark: SafeInvoke and BackgroundWorker don't solve the exact same problem, although in many cases you can choose either one of them. In general, SafeInvoke is much simpler to call and can be used to run just any UI function on a control. However, if you want your code to run asynchronously and get various progress events, you'll probably want to use the BackgroundWorker instead.
Another feature I'm missing in the SafeInvokeHelper is the ability to call a non-UI function through the Invoke method of a UI control. In other words, sometimes you centralize several operations on a control in a private method, and you want this method to be executed with the control's Invoke method. This scenario is not currently supported by the SafeInvokeHelper, since it requires the method passed as argument to belong to the control on which it is executed.)

A few weeks ago I posted a message about SafeInvoke – an elegant solution to use the correct thread for UI methods (reminder – a control should only be accessed by the thread that created it).
Well, in .NET 2.0 they introduced the BackgroundWorker object, which can be used to fix that exact problem (among others). In addition, Juval Löwy has published quite some time ago an article about the BackgroundWorker , how it works and how to work with it. In addition, he developed a similar BackgroundWorker for .NET 1.1, which will allow you to transparently migrate your code from .NET 1.1 to 2.0 (assuming you haven’t done it already…).

A few related links:
Juval's article
IDesign - Juval's company - it's a great site, loaded with useful tips, demos, ready-to-use classes etc.
MSDN's documentation for the BackgroundWorker class in .NET 2.0


John Wood said...

I wouldn't necessarily say it fixes that same exact problem... BackgroundWorker facilitates the implementation of one very specific (yet admittedly common) scenario where you want to do some work on a new thread and safely notify the UI thread of progress and completion. SafeInvoke lets you call *any* UI function, not just progress indicator code. It also allows you to do this with just one line rather than instantiating a new component and handling events. Thanks for mentioning my post btw.

John Wood said...

Thanks for clarifying in your post. As for your feature request - I'm not totally sure I understand, could you elaborate? I think what you're saying is that you want SafeInvokeHelper to be able to invoke private methods, not just public ones -- but i'm not sure. Perhaps you could leave an example as a comment on my blog?