Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Control.Invoke with input Parameters

From what I've found in C#, the Control.Invoke method requires that you use a delegate with no input parameters. Is there any way around this? I would like to invoke a method to update the UI from another thread and pass to string parameters to it.

like image 659
Adam Haile Avatar asked Apr 23 '09 23:04

Adam Haile


People also ask

What is the difference between Invoke and BeginInvoke method in C#?

Invoke : Executes on the UI thread, but calling thread waits for completion before continuing. Control. BeginInvoke : Executes on the UI thread, and calling thread doesn't wait for completion.

What is invoke () C#?

Invoke is used to call a method on the UI thread — without it you can cause an exception by updating the UI from another thread. And so if InvokeRequires returns true it means that you are not running in the UI thread and should use Control. Invoke to run the call in the right thread.


2 Answers

Which version of C# are you using? If you are using C#3.5 you can use closures to avoid passing in parameters.

With C#3.5
public static class ControlExtensions
{
  public static TResult InvokeEx<TControl, TResult>(this TControl control,
                                             Func<TControl, TResult> func)
    where TControl : Control
  {
    return control.InvokeRequired
            ? (TResult)control.Invoke(func, control)
            : func(control);
  }

  public static void InvokeEx<TControl>(this TControl control,
                                        Action<TControl> func)
    where TControl : Control
  {
    control.InvokeEx(c => { func(c); return c; });
  }

  public static void InvokeEx<TControl>(this TControl control, Action action)
    where TControl : Control
  {
    control.InvokeEx(c => action());
  }
}

Safely invoking code now becomes trivial.

this.InvokeEx(f => f.label1.Text = "Hello World");
this.InvokeEx(f => this.label1.Text = GetLabelText("HELLO_WORLD", var1));
this.InvokeEx(() => this.label1.Text = DateTime.Now.ToString());

With C#2.0 it becomes less trivial
public class MyForm : Form
{
  private delegate void UpdateControlTextCallback(Control control, string text);
  public void UpdateControlText(Control control, string text)
  {
    if (control.InvokeRequired)
    {
      control.Invoke(new UpdateControlTextCallback(UpdateControlText), control, text);
    }
    else
    {
      control.Text = text;
    }
  }
}

Using it simple, but you have to define more callbacks for more parameters.

this.UpdateControlText(label1, "Hello world");
like image 185
Samuel Avatar answered Sep 17 '22 13:09

Samuel


Some more possibilities:

this.Invoke(new MethodInvoker(() => this.DoSomething(param1, param2)));

or

this.Invoke(new Action(() => this.DoSomething(param1, param2)));

or even

this.Invoke(new Func<YourType>(() => this.DoSomething(param1, param2)));

where the first option is the best one, because MethodInvoker is concepted for that purposes and has a better performance.

like image 38
Denis T Avatar answered Sep 17 '22 13:09

Denis T