Using the Invoke Design Pattern with Anonymous Methods

If you've done Windows forms development in .NET you've almost certainly seen the invoke design pattern before.

delegate void UpdateLabelTextCallback(string message);

void UpdateLabelText(string message)
{
    if (InvokeRequired)
        Invoke(
            new UpdateLabelTextCallback(UpdateLabelText), 
            message
        );
    else
        label1.Text = message;
}

This pattern is required on methods that update the UI in some way but which are called from a thread other than the main/UI thread. Failing to use the invoke design pattern will usually result in an InvalidOperationException (cross-thread operation not valid) being thrown.

The code sample above shows the conventional implementation of the pattern using a delegate type which mirrors the method you're trying to callback and a call to Invoke with a reference back to the same method again. The InvokeRequired check decides whether an Invoke is necessary, and if it isn't, the method's normal logic is run.

Improving on This

The conventional implementation is both long-winded and messy, and it can really start to get ugly when a method gets separated from its callback delegate type when the delegate needs to go in a different #region. A moderately complex form may need dozens of methods that follow the invoke pattern, so you'll end up with large sections of code dedicated to callback delegates for specific methods.

Luckily, using anonymous methods we can do a lot better. Let's rewrite our example to use an anonymous method instead of a delegate type.

void UpdateLabelText(string message)
{
    if (InvokeRequired)
        Invoke(new MethodInvoker(
            delegate { UpdateLabelText(message); }
        ));
    else
        label1.Text = message;
}

Much better! Now if we wanted to, we could take advantage of the fact that a call to Invoke on the main thread will have no detrimental effect on our program and make this method even shorter.

void UpdateLabelText(string message)
{
    Invoke(new MethodInvoker(
        delegate { label1.Text = message; }
    ));
}

It's possible to put any amount of logic into the anonymous method that is being invoked, even if it's more than one or two lines. This is legal of course, but starts to look pretty sloppy pretty fast.

Now with Lambdas

Anything we can do with an anonymous method we can also do with a lambda expression. For cases like this, it doesn't matter much which type of function you use, but if you're using lambdas everywhere else in your application, you can stick with them for invoke patterns too.

void UpdateLabelText(string message)
{
    Invoke(new MethodInvoker(
        () => label1.Text = message
    ));
}

Posted on March 24, 2009 from Calgary

Newest Articles

About

My name is Brandur. I'm a polyglot software engineer and part-time designer working at Heroku in San Francisco, California. I'm a Canadian expat. My name is Icelandic. Drop me a line at brandur@mutelight.org.

Aside from technology, I'm interested in energy and how it relates to our society, travel, longboarding, muay thai, symphonic metal, and the guitar.

If you liked this article, consider finding me on Twitter.