1

In this post there's a very interesting way of updating UI threads using a static extension method.

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

What I want to do, is to make a generic version, so I'm not constrained by a control. This would allow me to do the following for example (because I'm no longer constrained to just being a Control)

this.progressBar1.InvokeIfRequired(pb => pb.Value = e.Progress);

I've tried the following:

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

But I get the following error that I'm not sure how to fix. Anyone any suggestions?

Error 5 Cannot convert lambda expression to type 'System.Delegate' because it is not a delegate type

Community
  • 1
  • 1
Ian
  • 33,605
  • 26
  • 118
  • 198
  • In fact... looking a bit closer, I seem to get the error on the first code example too... although I'm actually compiling for .NET 4.0 at the moment. – Ian Jun 12 '10 at 14:38

3 Answers3

4

replace :

c.Invoke(() => action(c));

with :

c.Invoke(action, c);
Thomas Levesque
  • 286,951
  • 70
  • 623
  • 758
0

This is a well known error with lambdas and anonymous methods:

Convert this delegate to an anonymous method or lambda

Your code just needs a cast to compile:

public static void InvokeIfRequired<T>(this T c, Action<T> action) where T : Control
{
    if (c.InvokeRequired)
    {
        c.Invoke((Action<T>)((control) => action(control)));
    }
    else
    {
        action(c);
    }
}
Community
  • 1
  • 1
bbudge
  • 1,127
  • 6
  • 7
0

Try this slight varient:

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

You need to cast it as a Delegate type. Kinda stupid I know. I can't really give you a good reason why a lambda expression isn't implicitly assignable as a delegate.

ckramer
  • 9,419
  • 1
  • 24
  • 38
  • It won't work, because `action` takes a parameter, and you're not passing it to `Invoke` – Thomas Levesque Jun 12 '10 at 17:08
  • good point. edited to account for that. for some reason I was thinking Invoke passed in the current control, which is totally not the case. – ckramer Jun 12 '10 at 17:28