Click here to Skip to main content
15,867,308 members
Articles / Desktop Programming / Windows Forms

Avoiding InvokeRequired

Rate me:
Please Sign up or sign in to vote.
4.83/5 (138 votes)
28 Jun 2012CPOL12 min read 492.9K   3.2K   246   73
How to avoid asking if InvokeRequired has the minimum code and no copy/paste

Image 1

Introduction to Second Version

This is a new, extended, improved version of my original article. This was (and is) my first (and only until now) CodeProject article. It was well rated, but at the same time, a lot of people offered corrections, alternatives and improvements. So I will use all this new information to show you a better way of doing the same thing. Every improvement in my code was suggested by someone else, so this is sort of collective writing. I'm just compiling things that you can read in the forum. But since I don't always read the forum, it makes sense to me to make some "text oriented maintenance". I will try to give everyone his own credit.

There are two solutions now inside the download, one for VS2008 with four projects (Desktop and Compact Framework for C# 3.5 and C# 2.0) and another one for VS2005 with four projects (Desktop and Compact Framework for C# 2.0, two different ways to solve the problem for each).

At the very end of the article, you will find what I think now is the "official" way (the Microsoft way) to solve this problem. I didn't know about this method until a couple of people posted it in the forum. At least read that (click here). But I will stick to my way of solving this issue. The following text is pretty much the exact text from the original article; the new text begins below the second horizontal line. Enjoy!

Introduction

As you should already now, using Windows.Forms gets really ugly when you need to access the user interface from multiple threads. IMHO, this is an example of leaky abstraction. I don't know (and I don't want to know) why I can't simply write:

C#
this.text = "New Text";

In any thread, the Windows.Forms.Control class should abstract me for any threading issue. But it doesn't. I will try to show several ways to solve this problem, and then finally, the simplest solution I've found. Wait until the end to find the good stuff (or click here)!

One thing worth knowing: When you run a program with this UI threading issue from within Visual Studio, it will always throw an exception. The same program running as a standalone EXE may not throw the exception. That is to say, the development environment is stricter than the .NET Framework. This is a good thing, it is always better to solve problems in development time that have random issues in production.

This is my first article and English is not my language, so please be gentle!

The "Standard" Pattern

I don't know who came out with this code at first, but this is the standard solution for the threading issue:

C#
public delegate void DelegateStandardPattern();
private void SetTextStandardPattern()
{
    if (this.InvokeRequired)
    {
        this.Invoke(new DelegateStandardPattern(SetTextStandardPattern));
        return;
    }
    this.text = "New Text";
}

Good points about this solution:

  • It does the job.
  • It works with C# 1.0, 2.0, 3.0, 3.5, Standard and Compact Framework (since CF 1.1, you don't have InvokeRequired in CF 1.0).
  • Everyone uses it, so when you read something like this, you know this code will be probably called from another thread.

Bad points:

  • It's a lot of code for updating a text!
  • You need to copy/paste it, you can't make a generic method from it.
  • If you need to call a method with parameters, you can't even reuse the delegate. You need to declare another delegate for each different parameter set.
  • It's ugly. I know this is subjective, but it is. I especially hate the need to declare a delegate "outside" the method.

There are some clever solutions out there, like this one using AOP, and this one using Reflection. But I wanted something easier to implement. One way to go could be a SurroundWith code snippet, but I like my code issues to be solved by the language, not by the IDE. Also, it will only solve the copy/paste problem, it will still be a lot of code for something really simple.

Why can't we generalize the standard pattern? Because there is no way in .NET 1.0 to pass a block of code as a parameter, because when C# started, it had almost no support for a functional programming style.

The "Anonymous Delegate" Pattern

With C# 2.0, we get anonymous delegates and the MethodInvoker class, so we could simplify the standard pattern into this:

C#
private void SetTextAnonymousDelegatePattern()
{
    if (this.InvokeRequired)
    {
        MethodInvoker del = delegate { SetTextAnonymousDelegatePattern(); };
        this.Invoke(del);
        return;
    }
    this.text = "New Text";
}

This is a slightly better solution, but I've never seen anyone using it. But what happens if instead of executing this.text = "New Text"; you need to call a method with parameters? Something like:

C#
private void MultiParams(string text, int number, DateTime dateTime);

There is no big deal, since delegates can access outer variables. So, you can write something like this:

C#
private void SetTextDelegatePatternParams(string text, int number, DateTime datetime)
{
    if (this.InvokeRequired)
    {
        MethodInvoker del = delegate { 
		SetTextDelegatePatternParams(text, number, datetime); };
        this.Invoke(del);
        return;
    }
    MultiParams(text, number, datetime);
}

The "Anonymous delegate" pattern can be minimized a lot if you "forget" to ask if invoke is required. That leads us to...

The "Anonymous Delegate Minimized" Pattern

This is really good:

C#
//No parameters
private void SetTextAnonymousDelegateMiniPattern()
{
    Invoke(new MethodInvoker(delegate
    {
    	this.text = "New Text";
    }));
}
//With parameters
private void SetTextAnonymousDelegateMiniPatternParams
		(string text, int number, DateTime dateTime)
{
    Invoke(new MethodInvoker(delegate
    {
    	MultiParams(text, number, dateTime);
    }));
}

It works, it's easy to write, it's only a few lines away from perfect. The first time I saw this, I thought that's what I was looking for. So what's the problem? Well, we forgot to ask if Invoke was required. And since this is not the standard way to do it, it will not be clear to others (or to ourselves in a couple of months) why we are doing this. We could be nice and comment the code, but let's be honest, we all know we won't. At least I prefer my code to be more "intention revealing". So, we have...

The "UIThread" Pattern, or the Way I've Solved this Problem

First, I show you the rabbit:

C#
//No parameters
private void SetTextUsingPattern()
{
    this.UIThread(delegate
    {
    	this.text = "New Text";
    });
}
//With parameters
private void SetTextUsingPatternParams(string text, int number, DateTime dateTime)
{
    this.UIThread(delegate
    {
    	MultiParams(text, number, dateTime);
    });
}

And now, I'll show you the trick. It's a simple static class with only one method. It's an extension method, of course, so if you have some objections like "extension methods are not pure object orientated programming", I recommend you to use Smalltalk and stop complaining. Or use a standard helper class, as you wish. Without comments, namespace and using, the class looks like this:

C#
static class FormExtensions
{
    static public void UIThread(this Form form, MethodInvoker code)
    {
        if (form.InvokeRequired)
        {
            form.Invoke(code);
            return;
        }
        code.Invoke();
    }
}

That was how far I've gone by myself. But then, I got the following suggestions from the developers in the forum:

  • was333 said: Why just Form? Why not Control? He was right. There's even a more abstract interface (ISynchronizeInvoke) that Rob Smiley suggested, but I feel it is way too strange, and is not present in Compact Framework
  • Borlip pointed that MethodInvoker isn't present in CompactFramework but Action is, so it's more portable to use Action
  • tzach shabtay has linked to this article pointing that it's better to use BeginInvoke than Invoke when possible. Sometimes, that could be a problem, so we need two versions. But you should prefer BeginInvoke.

So this is, until now, the final version:

C#
static class ControlExtensions
{
    static public void UIThread(this Control control, Action code)
    {
        if (control.InvokeRequired)
        {
            control.BeginInvoke(code);
            return;
        }
        code.Invoke();
    }
	
    static public void UIThreadInvoke(this Control control, Action code)
    {
        if (control.InvokeRequired)
        {
            control.Invoke(code);
            return;
        }
        code.Invoke();
    }
}

You can use it this way:

this.UIThread(delegate
{
   textBoxOut.Text = "UIThread pattern was used";
});

As you can see, is just the standard pattern, as generalized as possible. Good points about this solution:

  • It does the job.
  • It works the same with Full and Compact Framework.
  • It's simple (almost looks like a using{} block!).
  • It doesn't care if you have parameters or not.
  • If you read it again in three months, it will still look clear.
  • It uses a lot of what modern .NET has to offer: Anonymous delegates, extension methods, lambda expressions (if you want, see later).

Bad points:

  • Er ... waiting for your comments. Again.

Points of Interest

You can write even less code using lambda style, if you only need to write one line, you can do something as small as:

C#
private void SetTextUsingPatternParams(string text, int number, DateTime dateTime)
{
    this.UIThread(()=> MultiParams(text, number, dateTime));
}

and still be clear! If you need to read from the Form, you need to use UIThreadInvoke, or you will find strange results.

C#
private void Read()
{
     string textReaded;
     this.UIThreadInvoke(delegate
     {
        textReaded = this.Text;
     });
}

But I'm pretty sure that if you are reading the screen from another thread, you are making a mistake somewhere.

For C# 2.0 and Visual Studio 2008

This code needs .NET Framework 3.5 to work. It works out of the box with both Desktop and Compact Framework. You have a working sample for both in the downloadable code. Some people asked about a .NET 2.0 version. There are two things from .NET 3.5 that we miss in 2.0:

  1. Action class: We have Action<T>, but there is no simple-without-parameter-type Action, because Action is in System.Core.dll. That's easy, we just create the delegate inside System namespace:
C#
namespace System
{
    public delegate void Action();
}
  1. Extension Methods: Thanks to Kwan Fu Sit who pointed to this article, there is a clever way to do that if you can use Visual Studio 2008. Since Extension methods are just a compiler trick, the only thing you need to add to your project is a new class:
C#
namespace System.Runtime.CompilerServices
{
    [AttributeUsage
    (AttributeTargets.Method|AttributeTargets.Class|AttributeTargets.Assembly)]
    public sealed class ExtensionAttribute : Attribute
    {

    }
}

and that's it! It's very useful, not only for this UIThread trick. I've added both ExtensionAttribute and Action in the same file CSharp35Extras.cs. Check the details in the respective projects of the same solution. Once again, the exact same code works in both Desktop and Compact framework.

For C# 2.0 and Visual Studio 2005

I've found basically three ways to make it work in VS2005 and none of them are very elegant. In all of them, I use MethodInvoker instead of Action because MethodInvoker is present in the desktop .NET Framework 2.0. You still need to declare the MethodInvoker class somewhere if you work in Compact Framework. For simple one-window-project, (or one-window-with-multithreading-issues, to be precise), just copy a method inside the FormWathever.cs.

C#
private void UIThread(MethodInvoker code)
{
    if (this.InvokeRequired)
    {
        this.BeginInvoke(code);
        return;
    }
    this.Invoke();
}

You can use it like this:

C#
UIThread(delegate
{
   textBoxOut.Text = "UIThread pattern was used";
});

I think this is a good enough solution for simple projects. But when you have the same problem in a second window and you start copy/pasting the method, it's not so good.

Another option is to create a helper class like this:

C#
static public class UIHelper
{
    static public void UIThread(Control control, MethodInvoker code)
    {
        if (control.InvokeRequired)
        {
            control.BeginInvoke(code);
            return;
        }
        control.Invoke();
    }	
}

And then invoke the UIThread like this:

C#
UIHelper.UIThread(this, delegate
{
   textBoxOut.Text = "New text";
});

I have no problem having a UIHelper class, I always end up using a UIHelper class for one reason or another, but I don't like the UIHelper.UIThread(this,... part. It's too verbose to me. But it works, and at least you are not copy/pasting code.

Another way is to create a FormBase class like this:

C#
public class FormBase : Form
{
   public void UIThread(MethodInvoker code)
   {
       if (this.InvokeRequired)
       {
           this.BeginInvoke(code);
           return;
       }
       code.Invoke();
   }
}

then inherit all your forms from FormBase, and then invoke like this:

C#
UIThread(delegate
{
   textBoxOut.Text = "New text";
});

The invoking part is fine, but I don't enjoy inheriting all my forms from FormBase, specially because sometimes, when I am using visual inheritance, and I switch to design mode, Visual Studio shows me really horrible screens like this one:

Image 2

(Regarding this problem, the only solution I know when it happens is to close all Design tabs, then Build-Clear Solution, then close Visual Studio, then delete all files under bin and obj folders, reopen Visual Studio and Rebuild Solution and then reopen the FormWhatever in design view)

You are also losing the Control generalization; this way only works for Forms. Is up to you to choose one of these partial solutions, or migrate to VS2008, or to put pressure in your boss to migrate to VS2008. Came on! VS2010 is just around the corner.

For C# 1.0 and Visual Studio 2003

Are you kidding me? (I mean, I don't have a solution for that environment, and I don't think it's possible.)

Alternatives

When I wrote the first version of this article, I was aware of some alternatives to avoid copy/pasting code. I didn't like any of them, that was my motivation, but I listed those alternatives at the beginning of the article in order to show them to everyone. However, there was another alternative that I didn't think about: Alomgir Miah A suggested to use BackgroundWorker. I think it's too verbose, and it doesn't exist in Compact Framework. But sure, it exists in the full framework, and it can be used to avoid threading issues.

Two people suggested to use Control.CheckForIllegalCrossThreadCalls = false;. DON'T DO THAT! That is terribly wrong! From the MSDN documentation: illegal cross-thread calls will always raise an exception when an application is started outside the debugger... Setting Control.CheckForIllegalCrossThreadCalls = false; will only disable the debugger capability to detect all possible threading issues. So, you may not detect them when debugging, but when your app is running you may have horrible exceptions killing your app and have never been able to reproduce them. You are choosing to close your eyes when crossing the street. It's easy to do, but risky. Again, DON'T DO THAT!. Use whatever solution works for you, never ever write Control.CheckForIllegalCrossThreadCalls = false;.

The "Official" Pattern

Finally, two other people (Islam ElDemery and Member 170334, who has no name and no friendly URL) showed me what I think is the official solution that Microsoft has developed for this problem, and so it's probably better than mine: The SynchronizationContext class. I have to admit I didn't know about that, and it's been available since .NET Framework 2.0! It can be used very much like my own solution, and it's probably faster, since it's included in the framework, and it offers you more options. I am adult enough to show this solution here, even when it makes my own work pretty useless, and I am kid enough to reject it later. It's a two step solution: First, you need a SynchronizationContext member that must be initialized inside the constructor:

C#
class FormWathever
{
    private SynchronizationContext synchronizationContext ;
	
	public FormWathever()
	{
	    this.synchronizationContext  = SynchronizationContext.Current;
		//the rest of your code
	}
}

and then, when you need to do some thread-unsafe form actualizations, you should use something like this:

C#
synchronizationContext.Send(new SendOrPostCallback( 
    delegate(object state) 
    {    
        textBoxOut.Text = "New text";
    } 
), null);

It works, it's incorporated into the framework, I'm sure it's fast, and has some extra options. Why not to use it? I only can think in four reasons, and not very good ones. They look more like excuses.

  1. I don't like the initialization part. I don't understand why Microsoft didn't include a SynchronizationContext property inside the Form class, automatically initialized in the base constructor. In order to skip initialization by yourself, you need to inherit all your forms from a FormBase or something like this.
  2. It's kind of verbose. You need to create that SendOrPostCallback object, and pass that extra null parameter, and the extra object state. You could avoid this extra work by using another helper method, but in this case, I'll stick to UIThread.
  3. It's not "intention revealing code". And since it's not very popular, it makes your code harder to understand and maintain by others. (But not too much, let's be honest.)
  4. It doesn't exist in Compact Framework.

But if you don't need to care about Compact Framework, and you think that some extra typing will not kill you, that's probably the way to go.

History

  • 24th June, 2009: Initial version
  • 29th August, 2009: Extended version, several improvements, support for C# 2.0, some support for VS2005, and the "Official" pattern

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) TheWarrantyGroup
Argentina Argentina
I'm a Java/C# developer, with (some) experience in mobile and web development. I enjoy learning useful (and useless) stuff to be a better developer. I like to share the (little amount of) knowledge I have, by creating libraries and utility classes. CodeProject rocks! I wonder why the Java part is not so popular...

Comments and Discussions

 
PraiseFive stars Pin
FriedCesar12-Apr-21 17:58
FriedCesar12-Apr-21 17:58 
QuestionSolid analysis! Pin
Nicholas Ryan Spencer4-Sep-14 2:47
Nicholas Ryan Spencer4-Sep-14 2:47 
GeneralMy vote of 5 Pin
Viperbite66619-Jun-13 22:36
Viperbite66619-Jun-13 22:36 
GeneralMy vote of 5 Pin
MarkBoreham9-Jun-13 10:54
professionalMarkBoreham9-Jun-13 10:54 
QuestionInvoke without InvokeRequired Pin
Nicolas Krzywinski22-Apr-13 22:38
Nicolas Krzywinski22-Apr-13 22:38 
GeneralMy vote of 4 Pin
YassJD11-Jan-13 1:37
YassJD11-Jan-13 1:37 
QuestionAn alternative to Action/MethodInvoker Pin
João Martins21-Dec-12 11:37
João Martins21-Dec-12 11:37 
QuestionMethodInvoker/Action in the "Anonymous delegate minimized" Pattern Pin
Thomas Daniels18-Dec-12 7:27
mentorThomas Daniels18-Dec-12 7:27 
GeneralMy vote of 5 Pin
Sperneder Patrick5-Oct-12 3:53
professionalSperneder Patrick5-Oct-12 3:53 
GeneralMy vote of 5 Pin
Andrei Straut19-Sep-12 7:12
Andrei Straut19-Sep-12 7:12 
Questionwhat if we have multiple controls Pin
AhmadHamid27-Aug-12 2:19
AhmadHamid27-Aug-12 2:19 
QuestionGeneral Comment Pin
Kountree20-Jul-12 3:55
Kountree20-Jul-12 3:55 
GeneralMy vote of 5 Pin
BloodyBaron8-Jul-12 10:18
BloodyBaron8-Jul-12 10:18 
GeneralMy vote of 5 Pin
JPPower7-Jul-12 0:34
JPPower7-Jul-12 0:34 
SuggestionLess code for SynchronizationContext Pin
saiarcot8955-Jul-12 2:49
saiarcot8955-Jul-12 2:49 
QuestionTaskScheduler.FromCurrentSynchronizationContext() ~ what about this? Pin
MAIsw2-Jul-12 21:08
MAIsw2-Jul-12 21:08 
AnswerRe: TaskScheduler.FromCurrentSynchronizationContext() ~ what about this? Pin
Pablo Grisafi4-Jul-12 2:28
Pablo Grisafi4-Jul-12 2:28 
GeneralMy vote of 5 Pin
koenir2-Jul-12 12:04
professionalkoenir2-Jul-12 12:04 
GeneralMy vote of 5 Pin
Dr Bob2-Jul-12 10:05
Dr Bob2-Jul-12 10:05 
QuestionSynchronization in control or caller? Pin
supercat929-Jun-12 9:13
supercat929-Jun-12 9:13 
GeneralMy vote of 5 Pin
Brian Pendleton29-Jun-12 0:18
Brian Pendleton29-Jun-12 0:18 
QuestionVB.NET Version Pin
Member 43764225-Jun-12 10:14
Member 43764225-Jun-12 10:14 
AnswerRe: VB.NET Version Pin
Akinmade Bond13-Oct-12 1:24
professionalAkinmade Bond13-Oct-12 1:24 
GeneralRe: VB.NET Version Pin
Ravi Kant Srivastava8-Apr-13 5:12
professionalRavi Kant Srivastava8-Apr-13 5:12 
GeneralMy vote of 5 Pin
DennisKuhn7-May-12 13:23
DennisKuhn7-May-12 13:23 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.