Reputation: 31359
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.
Upvotes: 13
Views: 26659
Reputation: 1
private void ppTrace(string tv)
{
if (_Txb1.InvokeRequired)
{
_Txb1.Invoke((Action<string>)ppTrace, tv);
}
else
{
_Txb1.AppendText(tv + Environment.NewLine);
}
}
Upvotes: 0
Reputation: 442
Here ya go using lambda expressions with the Invoke() extension + an input parameter.
Using: action(STARS db)
_ccb.GetImagerFRU_PartNbr().Invoke(new Action<STARS>(dbase => _ccb.GetImagerFRU_PartNbr().Text = dbase.PartNumber(serial) ?? String.Empty), db);
Upvotes: 1
Reputation: 81
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.
Upvotes: 8
Reputation: 4523
Why not
tvMatrix.Invoke((MethodInvoker) (() => {
tvMatrix.Nodes[0].Nodes.Add(id.ToString(), typename);
}));
Upvotes: 0
Reputation: 27937
Found an elegant method for .net 2.0 with anonymous methods wrapped in a MethodInvoker Delegate. That way is no need to define own delegates all the time. Example:
private void InitUI(Guid id, string typename)
{
MethodInvoker inv = delegate{tvMatrix.Nodes[0].Nodes.Add(id.ToString(), typename);};
tvMatrix.Invoke(inv);
}
Upvotes: 0
Reputation: 8186
As Luke says, use Control.Invoke like this...
For example in a form:
public delegate void DelegatePassMessages(string name, int value);
public DelegatePassMessages passMessage;
In the contructor:
passMessage = new DelegatePassMessages (this.MessagesIn);
Then the MessagesIn function to receive data:
public void MessagesIn(string name, int value)
{
}
Then to pass data to your form:
formName.Invoke(formName.passMessage, new Object[] { param1, param2});
Upvotes: 6
Reputation: 4867
I think Samuel's (excellent) approach can be pushed even more:
Extension Method:
public static void ExecuteAsync<TControl>(this TControl control, Action action)
where TControl : Control
{
new Thread(() =>
{
control.Invoke(action);
})
.Start();
}
Form code:
private void doStuff()
{
this.ExecuteAsync(() =>
{
// Do your stuff in a separate thread
// but having full access to local or instance variables.
// No (visible) threading code needs to be used here.
});
}
Upvotes: 1
Reputation: 38356
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.5public 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());
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");
Upvotes: 23