Whenever one needs to interact with WinForms UI from within another thread (the one that didn’t create the UI controls) one has to rely on the Control.Invoke (or BeginInvoke/EndInvoke pair) method. Otherwise one gets an InvalidOperationException exception with message “Cross-thread operation not valid: Control ‘name here’ accessed from a thread other than the thread it was created on”. This happens because WinForms (and .net framework in general) isn’t thread safe.
Let’s say I want to know how many controls are on the form. I’d do it like this (Form f holds the instance of the Form created in some thread):
This way the method GetControlsCount is thread safe. That’s fine. But what should I do if I require to access many methods in such a thread safe way (I’ll blog about the reason I need it in a future post)? Creating this kind of wrapper for every different method I need to call would be kind of boring at best and difficult to maintain, don’t you think?
So I created a generic method instead, like this:
This is much better because I don’t need to create a wrapper for each method – instead I merely provide a delegate (of type Func<int> in my case). There are two drawbacks to this approach.
1. It won’t work with different number of parameters nor it will work with methods (= actions) that don’t return a value. The only workaround is to create various similar methods that accepts different argument number and return either a result or no result (void). Here is a bunch of such variations:
2. Passing Control parameter (which is required to do the synchronization) is such pre .net 3.5-ish. Instead extensions methods can be used, like this:
So the final version of the call to InvokeSync looks even nicer: