206

I have become painfully aware of just how often one needs to write the following code pattern in event-driven GUI code, where

private void DoGUISwitch() {
    // cruisin for a bruisin' through exception city
    object1.Visible = true;
    object2.Visible = false;
}

becomes:

private void DoGUISwitch() {
    if (object1.InvokeRequired) {
        object1.Invoke(new MethodInvoker(() => { DoGUISwitch(); }));
    } else {
        object1.Visible = true;
        object2.Visible = false;
    }
}

This is an awkward pattern in C#, both to remember, and to type. Has anyone come up with some sort of shortcut or construct that automates this to a degree? It'd be cool if there was a way to attach a function to objects that does this check without having to go through all this extra work, like a object1.InvokeIfNecessary.visible = true type shortcut.

Previous answers have discussed the impracticality of just calling Invoke() every time, and even then the Invoke() syntax is both inefficient and still awkward to deal with.

So, has anyone figured out any shortcuts?

Community
  • 1
  • 1
Tom Corelis
  • 4,990
  • 11
  • 35
  • 48
  • 2
    I've wondered the same thing, but in regards to WPF's Dispatcher.CheckAccess(). – Taylor Leese Mar 02 '10 at 23:35
  • I thought up a rather crazy suggestion inspired by your `object1.InvokeIfNecessary.Visible = true` line; check out my updated answer and let me know what you think. – Dan Tao Mar 03 '10 at 00:05
  • 1
    Add a Snippet to help implement method suggested by Matt Davis: see my answer (late but just showing how for later readers ;-) ) – Aaron Gage Feb 15 '11 at 13:40
  • 3
    I don't understand why Microsoft did nothing to simplify that in .NET. Creating delegates for each change on form from thread is really annoying. – Kamil Oct 15 '12 at 17:26
  • @Kamil I couldn't agree more! This is such an oversight, given its ubiquity. Within the framework, just handle the threading if necessary. Seems obvious. – SteveCinq Feb 20 '19 at 21:22

9 Answers9

160

Lee's approach can be simplified further

public static void InvokeIfRequired(this Control control, MethodInvoker action)
{
    // See Update 2 for edits Mike de Klerk suggests to insert here.

    if (control.InvokeRequired) {
        control.Invoke(action);
    } else {
        action();
    }
}

And can be called like this

richEditControl1.InvokeIfRequired(() =>
{
    // Do anything you want with the control here
    richEditControl1.RtfText = value;
    RtfHelpers.AddMissingStyles(richEditControl1);
});

There is no need to pass the control as parameter to the delegate. C# automatically creates a closure.

If you must return a value, you can use this implementation:

private static T InvokeIfRequiredReturn<T>(this Control control, Func<T> function)
{
    if (control.InvokeRequired) {
        return (T)control.Invoke(function);
    } else {
        return function();
    }
}

UPDATE:

According to several other posters Control can be generalized as ISynchronizeInvoke:

public static void InvokeIfRequired(this ISynchronizeInvoke obj,
                                         MethodInvoker action)
{
    if (obj.InvokeRequired) {
        var args = new object[0];
        obj.Invoke(action, args);
    } else {
        action();
    }
}

DonBoitnott pointed out that unlike Control the ISynchronizeInvoke interface requires an object array for the Invoke method as parameter list for the action.


UPDATE 2

Edits suggested by Mike de Klerk (see comment in 1st code snippet for insert point):

// When the form, thus the control, isn't visible yet, InvokeRequired  returns false,
// resulting still in a cross-thread exception.
while (!control.Visible)
{
    System.Threading.Thread.Sleep(50);
}

See ToolmakerSteve's and nawfal's comments below for concerns about this suggestion.

Olivier Jacot-Descombes
  • 104,806
  • 13
  • 138
  • 188
  • 2
    Wouldn't be better to have `ISynchronizeInvoke` instead of `Control`? (Kudos to Jon Skeet http://stackoverflow.com/questions/711408/best-way-to-invoke-any-cross-threaded-code/711414#711414) – Odys Jun 09 '13 at 20:15
  • @odyodyodys: Good point. I didn't know about `ISynchronizeInvoke`. But the only type which derives from it (according to Reflector) is `Control`, so the adavantage is limited. – Olivier Jacot-Descombes Jun 10 '13 at 12:19
  • Note: if you go with `ISynchronizeInvoke`, you will _not_ be able to simply use `control.Invoke(action);`, as there is no one-parameter version. Only `Control` offers that. – DonBoitnott Jun 23 '14 at 17:43
  • Q: Would it make sense to lock the control, because action() could contain many operations on that control? In other words, the line "action();" would be "lock(control) action();" ? I can't think of any drawbacks to doing this, but I could be missing something. – mike Apr 27 '15 at 19:26
  • No. The controls can only be manipulated in the UI-thread. This is the very point of this `Invoke`. I.e. any other thread has to **invoke** the control. This means that his invoked actions will be performed in the UI-thread. The UI-thread will only allow to be invoked when being idle. I.e. code running in the UI-thread will never be interrupted by other UI-thread code. It can be interrupted by other threads; however, those cannot manipulate the controls themselves; but they can manipulate data the controls are relying on. Therefore you will possibly have to lock the data, not the control. – Olivier Jacot-Descombes Apr 28 '15 at 13:49
  • Are there any disadvantages to applying the extension method at the form level rather than at the control level? I have a data model that fires a few events and the form has handlers for them. I was considering adding the `InvokeIfRequired` call as a generic wrapper within those handlers. – OttPrime Jul 17 '15 at 15:38
  • Invoking means: wait until the UI-thread is idle, i.e., wait until any running event handlers finish their execution, and then run the method (or delegate) being invoked on the UI-thread. Therefore it makes no difference, whether you call it on the form or any control. [Control.Invoke Method (Delegate)](https://msdn.microsoft.com/en-us/library/zyzhdc6b%28v=vs.110%29.aspx?f=255&MSPPError=-2147217396) says: "The Invoke method searches up the control's parent chain until it finds a control or form that has a window handle if the current control's underlying window handle does not exist yet." – Olivier Jacot-Descombes Jul 17 '15 at 16:27
  • 7
    @mike-de-clerk, I am concerned about your suggestion to add `while (!control.Visible) ..sleep..`. To me that has a bad code smell, as it is a potentially unbounded delay (maybe even an infinite loop in some cases), in code that may have callers who are not expecting such a delay (or even a deadlock). IMHO, any use of `Sleep` should be the responsibility of each caller, OR should be in a separate wrapper that is clearly marked as to its consequences. IMHO, usually it would be better to "fail hard" (exception, to catch during testing), or to "do nothing" if the control is not ready. Comments? – ToolmakerSteve May 16 '16 at 23:27
  • 3
    The while (!Visible) needs a timeout. Bad practice that could lead to an infinite loop that would be difficult to debug. – rollsch Dec 02 '16 at 00:40
  • `MethodInvoker` introduces an unnecessary dependency to `Windows.Forms` – nurettin Oct 22 '17 at 18:17
  • 2
    It does not, because we are invoking on winforms controls anyway. See also https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.methodinvoker?view=netframework-4.7 – Olivier Jacot-Descombes Oct 22 '17 at 18:47
  • 1
    @OlivierJacot-Descombes,It would be great , if you please explain how thread.invokerequired works behind? – Sudhir.net Nov 28 '18 at 06:08
  • 1
    `InvokeRequired` tells whether the calling thread is different from the thread that created the control. `Invoke` passes the action from the calling thread to the control's thread where it is executed. This ensures that, for instance, a click event handler is never interrupted. – Olivier Jacot-Descombes Nov 28 '18 at 13:59
  • @Olivier Jacot-Descombes Say you wanted to add parameter object[] args = null. How would you use those arguments when obj.InvokeRequired==false? – Daniel P Jun 24 '21 at 20:02
  • This parameter is only required for `Invoke()`. If `InvokeRequired` is `false`, you can call your method directly: `action();`. (This is the `else` case in the UPDATE example.) – Olivier Jacot-Descombes Jun 25 '21 at 13:51
  • 2
    @OlivierJacot-Descombes, your assumption for *Update 2* is incorrect I think (besides the blocking `Thread.Sleep` calls). You say `When the form, thus the control, isn't visible yet, InvokeRequired returns false, resulting still in a cross-thread exception.`, but how plausible is this? If the window handle is not created for the control, wouldn't updating the control in a different thread anyway work? At that point its just setting values to an in-memory object. This is why the common `if (c.InvokeRequired) c.Invoke(foo); else foo();` pattern works so well. – nawfal Oct 12 '21 at 07:23
  • 1
    In fact, the naming of the property `InvokeRequired` is so apt. It just accurately tells you if Invoke is required. Invoke is required if you are on different thread and the control is created. If you are on a different thread and control handle is not yet created, then you are free to mutate controls! – nawfal Oct 12 '21 at 07:28
  • Note that this was a suggestion by Mike de Klerk. I have referenced you comment in the answer now. – Olivier Jacot-Descombes Oct 12 '21 at 12:13
139

You could write an extension method:

public static void InvokeIfRequired(this Control c, Action<Control> action)
{
    if(c.InvokeRequired)
    {
        c.Invoke(new Action(() => action(c)));
    }
    else
    {
        action(c);
    }
}

And use it like this:

object1.InvokeIfRequired(c => { c.Visible = true; });

EDIT: As Simpzon points out in the comments you could also change the signature to:

public static void InvokeIfRequired<T>(this T c, Action<T> action) 
    where T : Control
Lee
  • 142,018
  • 20
  • 234
  • 287
  • Maybe i'm just too dumb, but this code won't compile. So i fixed it as it built by me (VS2008). – Oliver Nov 18 '10 at 10:02
  • 5
    Just for completeness: In WPF there is a different dispatching mechanism, but it works rather analogous. You could use this extension method there: public static void InvokeIfRequired(this T aTarget, Action aActionToExecute) where T:DispatcherObject { if (aTarget.CheckAccess()) { aActionToExecute(aTarget); } else { aTarget.Dispatcher.Invoke(aActionToExecute); } } – Simon D. Nov 18 '10 at 13:16
  • 1
    I added an answer that simplifies Lee's solution slightly. – Olivier Jacot-Descombes Aug 29 '12 at 14:27
  • Hi, as I where using something similiar, there can be be a big problem coming from this generic implementation. If the Control is Disposing/Disposed, you will get a ObjectDisposedException. – Offler Jun 05 '13 at 06:51
  • @Offler - That has nothing to do with this method, and would occur if you called `Invoke` directly. You have a design problem if you find yourself regularly trying to access disposed controls. You could check for `IsDisposing` and `IsDisposed` first if you needed to. – Lee Jun 05 '13 at 08:19
  • @lee that won't help. IsDisPosing, IsDisposed, Handle Is not Available can occur between the statements, even if you check, directly after the check something else can dispose a control in a multithreadedd environment. – Offler Jun 05 '13 at 11:57
  • 1
    @Offler - Well if they're being disposed on a different thread you have a synchronisation problem, it's not an issue in this method. – Lee Jun 05 '13 at 12:24
41

Here's the form I've been using in all my code.

private void DoGUISwitch()
{ 
    Invoke( ( MethodInvoker ) delegate {
        object1.Visible = true;
        object2.Visible = false;
    });
} 

I've based this on the blog entry here. I have not had this approach fail me, so I see no reason to complicate my code with a check of the InvokeRequired property.

Hope this helps.

Michael Pakhantsov
  • 24,855
  • 6
  • 60
  • 59
Matt Davis
  • 45,297
  • 16
  • 93
  • 124
  • +1 - I stumbled on the the same blog entry you did, and think this is the cleanest approach of any proposed – Tom Bushell Apr 20 '10 at 19:27
  • 4
    There is a small performance hit using this approach, which could pile up when called multiple times. http://stackoverflow.com/a/747218/724944 – surfen Nov 29 '11 at 12:05
  • 8
    You have to use `InvokeRequired` if the code could be executed before the control was shown or you will have a fatal exception. – 56ka Jan 17 '14 at 14:28
10

Create a ThreadSafeInvoke.snippet file, and then you can just select the update statements, right click and select 'Surround With...' or Ctrl-K+S:

<?xml version="1.0" encoding="utf-8" ?>
<CodeSnippet Format="1.0.0" xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
  <Header>
    <Title>ThreadsafeInvoke</Title>
    <Shortcut></Shortcut>
    <Description>Wraps code in an anonymous method passed to Invoke for Thread safety.</Description>
    <SnippetTypes>
      <SnippetType>SurroundsWith</SnippetType>
    </SnippetTypes>
  </Header>
  <Snippet>
    <Code Language="CSharp">
      <![CDATA[
      Invoke( (MethodInvoker) delegate
      {
          $selected$
      });      
      ]]>
    </Code>
  </Snippet>
</CodeSnippet>
Aaron Gage
  • 2,373
  • 1
  • 16
  • 15
8

Here's an improved/combined version of Lee's, Oliver's and Stephan's answers.

public delegate void InvokeIfRequiredDelegate<T>(T obj)
    where T : ISynchronizeInvoke;

public static void InvokeIfRequired<T>(this T obj, InvokeIfRequiredDelegate<T> action)
    where T : ISynchronizeInvoke
{
    if (obj.InvokeRequired)
    {
        obj.Invoke(action, new object[] { obj });
    }
    else
    {
        action(obj);
    }
} 

The template allows for flexible and cast-less code which is much more readable while the dedicated delegate provides efficiency.

progressBar1.InvokeIfRequired(o => 
{
    o.Style = ProgressBarStyle.Marquee;
    o.MarqueeAnimationSpeed = 40;
});
gxtaillon
  • 1,016
  • 1
  • 19
  • 33
7

Usage:

control.InvokeIfRequired(c => c.Visible = false);

return control.InvokeIfRequired(c => {
    c.Visible = value

    return c.Visible;
});

Code:

using System;
using System.ComponentModel;

namespace Extensions
{
    public static class SynchronizeInvokeExtensions
    {
        public static void InvokeIfRequired<T>(this T obj, Action<T> action)
            where T : ISynchronizeInvoke
        {
            if (obj.InvokeRequired)
            {
                obj.Invoke(action, new object[] { obj });
            }
            else
            {
                action(obj);
            }
        }

        public static TOut InvokeIfRequired<TIn, TOut>(this TIn obj, Func<TIn, TOut> func) 
            where TIn : ISynchronizeInvoke
        {
            return obj.InvokeRequired
                ? (TOut)obj.Invoke(func, new object[] { obj })
                : func(obj);
        }
    }
}
Konstantin S.
  • 1,307
  • 14
  • 19
6

I'd rather use a single instance of a method Delegate instead of creating a new instance every time. In my case i used to show progress and (info/error) messages from a Backroundworker copying and casting large data from a sql instance. Everywhile after about 70000 progress and message calls my form stopped working and showing new messages. This didn't occure when i started using a single global instance delegate.

delegate void ShowMessageCallback(string message);

private void Form1_Load(object sender, EventArgs e)
{
    ShowMessageCallback showMessageDelegate = new ShowMessageCallback(ShowMessage);
}

private void ShowMessage(string message)
{
    if (this.InvokeRequired)
        this.Invoke(showMessageDelegate, message);
    else
        labelMessage.Text = message;           
}

void Message_OnMessage(object sender, Utilities.Message.MessageEventArgs e)
{
    ShowMessage(e.Message);
}
3

I Kind of like to do it a bit different, i like to call "myself" if needed with an Action,

    private void AddRowToListView(ScannerRow row, bool suspend)
    {
        if (IsFormClosing)
            return;

        if (this.InvokeRequired)
        {
            var A = new Action(() => AddRowToListView(row, suspend));
            this.Invoke(A);
            return;
        }
         //as of here the Code is thread-safe

this is a handy pattern, the IsFormClosing is a field that i set to True when I am closing my form as there might be some background threads that are still running...

-4

You should never be writing code that looks like this:

private void DoGUISwitch() {
    if (object1.InvokeRequired) {
        object1.Invoke(new MethodInvoker(() => { DoGUISwitch(); }));
    } else {
        object1.Visible = true;
        object2.Visible = false;
    }
}

If you do have code that looks like this then your application is not thread-safe. It means that you have code which is already calling DoGUISwitch() from a different thread. It's too late to be checking to see if it's in a different thread. InvokeRequire must be called BEFORE you make a call to DoGUISwitch. You should not access any method or property from a different thread.

Reference: Control.InvokeRequired Property where you can read the following:

In addition to the InvokeRequired property, there are four methods on a control that are thread safe to call: Invoke, BeginInvoke, EndInvoke and CreateGraphics if the handle for the control has already been created.

In a single CPU architecture there's no problem, but in a multi-CPU architecture you can cause part of the UI thread to be assigned to the processor where the calling code was running...and if that processor is different from where the UI thread was running then when the calling thread ends Windows will think that the UI thread has ended and will kill the application process i.e. your application will exit without error.

Steve Wood
  • 11
  • 1
  • Hey there, thanks for your answer. It's been years since I asked this question (and almost just as long a time since I've worked with C#), but I was wondering if you could explain a bit further? The docs you linked to refer to a specific danger of calling `invoke()` et al before the control is given a handle, but IMHO doesn't describe what you've described. The whole point of all this `invoke()` nonsense is to update the UI in a thread-safe manner, and I would think putting *more* instructions in a blocking context would lead to stuttering? (Ugh...glad I stopped using M$ tech. So complicated!) – Tom Corelis Nov 04 '14 at 17:48
  • I also want to note that despite frequent use of the original code (way back when), I did not observe the problem you described on my dual-CPU desktop – Tom Corelis Nov 04 '14 at 18:04
  • 3
    I doubt this answer is accurate as MSDN shows plenty of examples just like the OP gave. – public wireless Mar 25 '15 at 22:05