Using Anonymous Methods with Control.Invoke()

 

Just in case I’m the only person that didn’t know this, you can’t pass an anonymous method as an argument to Control.Invoke() when you’re trying to make cross-thread calls.  Instead, you have to wrap it in a Delegate like the MethodInvoker delegate like this code below:

 

   23         public string CurrentActivity

   24         {

   25             get { return _activityStrip.Text; }

   26             set

   27             {

   28                 if (InvokeRequired)

   29                 {

   30                     MethodInvoker invoker = new MethodInvoker(delegate()

   31                                                                   {

   32                                                                       _activityStrip.Text = value;

   33                                                                   });

   34                     Invoke(invoker);

   35                 }

   36                 else

   37                 {

   38                     _activityStrip.Text = value;

   39                 }

   40             }

   41         }

It’s fine and it works, but it’s butt ugly.  I’m mildly tempted to try out Boo for this very reason or maybe play with RubyCLR to drive WinForms with a cleaner syntax.

About Jeremy Miller

Jeremy is the Chief Software Architect at Dovetail Software, the coolest ISV in Austin. Jeremy began his IT career writing "Shadow IT" applications to automate his engineering documentation, then wandered into software development because it looked like more fun. Jeremy is the author of the open source StructureMap tool for Dependency Injection with .Net, StoryTeller for supercharged acceptance testing in .Net, and one of the principal developers behind FubuMVC. Jeremy's thoughts on all things software can be found at The Shade Tree Developer at http://codebetter.com/jeremymiller.
This entry was posted in Uncategorized. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • Aralmo

    And why not using locks or monitor? won’t an invoke be a bottleneck?

  • http://id.tomfanning.eu/ Tom Fanning

    public static class ExtensionMethods
    {
        public static void InvokeAction(this Control ctrl, Action act)
        {
            ctrl.Invoke(new MethodInvoker(act));
        }
    }

    Call with InvokeAction(()=>this.Textbox.Text = “123″);

  • Blair Davidson

    get { return _activityStrip.Text; }

    is that threadsafe???

    doesnt look like it

    i wrap get and sets with invokes

  • Dana Hanna

    In 3.5, you could create a simple extension method on the Control object with this overload which will allow a anony delegate to be passed to invoke:

    public static void Invoke(this Control c, MethodInvoker mi)
    {
    c.Invoke((Delegate)mi);
    }

  • Myrddin

    Also, you really should keep track of your last percentage and avoid doing the invoke all together unless the value has changed. Invokes by their very nature are slow and even if you don’t block on them it’ll be better for your application if you don’t invoke unless you absolutely have to.

  • Myrddin

    Try using BeginInvoke instead so your thread doesn’t block waiting for the target thread’s message loop.

  • http://www.netaffiliatebase.com Bhavesh

    I still think is has performance issues.

    I have taken an example to update progressbar while reading a huge file. If I update in unsafe way in the thread, the program executes amazingly fast.

    MethodInvoker myCallback = new MethodInvoker(
    delegate()
    {
    progressBar1.Value = m_iPercentage;
    });

    //progressbar percentage
    Double perRead = (Convert.ToDouble(fStream.Position) / Convert.ToDouble(fStream.Length)) * 100.0;
    m_iPercentage = Convert.ToInt32(perRead);
    progressBar1.Value = m_iPercentage;
    //Invoke(myCallback);

    as soon as i comment progressbar1.value = m_iPercentage; and run through Invoke(myCallback); the program runs hell lot slower.

    Do know what to do here.

  • http://davidkean.net David M. Kean

    Or why don’t you add an overload to your base Form that takes a MethodInvoker:

    public void Invoke(MethodInvoker invoker)
    {
    Invoke((Delegate)invoker);
    }

    Now you can call Invoke with an anonymous method.

  • Geert Baeyaert

    You can also cast the anonymous delegate to MethodInvoker.

    Invoke((MethodInvoker)delegate() { _activityStrip.Text = value; });

    Still not ideal, but better.