Having a bit of trouble with the syntax where we want to call a delegate anonymously within a Control.Invoke.
We have tried a number of different approaches, all to no avail.
For example:
myControl.Invoke(delegate() { MyMethod(this, new MyEventArgs(someParameter)); });
where someParameter is local to this method
The above will result in a compiler error:
Cannot convert anonymous method to type 'System.Delegate' because it is not a delegate type
Because Invoke
/ BeginInvoke
accepts Delegate
(rather than a typed delegate), you need to tell the compiler what type of delegate to create ; MethodInvoker
(2.0) or Action
(3.5) are common choices (note they have the same signature); like so:
control.Invoke((MethodInvoker) delegate {this.Text = "Hi";});
If you need to pass in parameters, then "captured variables" are the way:
string message = "Hi";
control.Invoke((MethodInvoker) delegate {this.Text = message;});
(caveat: you need to be a bit cautious if using captures async , but sync is fine - ie the above is fine)
Another option is to write an extension method:
public static void Invoke(this Control control, Action action)
{
control.Invoke((Delegate)action);
}
then:
this.Invoke(delegate { this.Text = "hi"; });
// or since we are using C# 3.0
this.Invoke(() => { this.Text = "hi"; });
You can of course do the same with BeginInvoke
:
public static void BeginInvoke(this Control control, Action action)
{
control.BeginInvoke((Delegate)action);
}
If you can't use C# 3.0, you could do the same with a regular instance method, presumably in a Form
base-class.
Actually you do not need to use delegate keyword. Just pass lambda as parameter:
control.Invoke((MethodInvoker)(() => {this.Text = "Hi"; }));
myControl.Invoke(new MethodInvoker(delegate() {...}))
You need to create a delegate type. The keyword 'delegate' in the anonymous method creation is a bit misleading. You are not creating an anonymous delegate but an anonymous method. The method you created can be used in a delegate. Like this:
myControl.Invoke(new MethodInvoker(delegate() { (MyMethod(this, new MyEventArgs(someParameter)); }));
For the sake of completeness, this can also be accomplished via an Action method/anonymous method combination:
//Process is a method, invoked as a method group
Dispatcher.Current.BeginInvoke((Action) Process);
//or use an anonymous method
Dispatcher.Current.BeginInvoke((Action)delegate => {
SomeFunc();
SomeOtherFunc();
});
I had problems with the other suggestions because I want to sometimes return values from my methods. If you try to use MethodInvoker with return values it doesn't seem to like it. So the solution I use is like this (very happy to hear a way to make this more succinct - I'm using c#.net 2.0):
// Create delegates for the different return types needed.
private delegate void VoidDelegate();
private delegate Boolean ReturnBooleanDelegate();
private delegate Hashtable ReturnHashtableDelegate();
// Now use the delegates and the delegate() keyword to create
// an anonymous method as required
// Here a case where there's no value returned:
public void SetTitle(string title)
{
myWindow.Invoke(new VoidDelegate(delegate()
{
myWindow.Text = title;
}));
}
// Here's an example of a value being returned
public Hashtable CurrentlyLoadedDocs()
{
return (Hashtable)myWindow.Invoke(new ReturnHashtableDelegate(delegate()
{
return myWindow.CurrentlyLoadedDocs;
}));
}
I like to use Action in place of MethodInvoker, it is shorter and looks cleaner.
Invoke((Action)(() => {
DoSomething();
}));
// OR
Invoke((Action)delegate {
DoSomething();
});
Eg.
// Thread-safe update on a form control
public void DisplayResult(string text){
if (txtResult.InvokeRequired){
txtResult.Invoke((Action)delegate {
DisplayResult(text);
});
return;
}
txtResult.Text += text + "\r\n";
}
I never understood why this makes a difference for the compiler, but this is sufficient.
public static class ControlExtensions
{
public static void Invoke(this Control control, Action action)
{
control.Invoke(action);
}
}
Bonus: add some error handling, because it is likely that, if you are using Control.Invoke
from a background thread you are updating the text / progress / enabled state of a control and don't care if the control is already disposed.
public static class ControlExtensions
{
public static void Invoke(this Control control, Action action)
{
try
{
if (!control.IsDisposed) control.Invoke(action);
}
catch (ObjectDisposedException) { }
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.