Анонимный метод в вызове Invoke
возникли некоторые проблемы с синтаксисом, где мы хотим вызвать делегат анонимно в элементе управления.Взывать.
мы пробовали несколько различных подходов, все безрезультатно.
например:
myControl.Invoke(delegate() { MyMethod(this, new MyEventArgs(someParameter)); });
где некоторый параметр является локальным для этого метода
выше приведет к ошибке компилятора:
невозможно преобразовать анонимный метод в тип ' System.Делегат", потому что это не делегат типа
7 ответов:
, потому что
Invoke/BeginInvokeпринимаетDelegate(а не типизированный делегат), вам нужно сказать компилятору, какой тип делегата создать;MethodInvoker(2.0) илиAction(3.5) являются общими вариантами (обратите внимание, что они имеют одинаковую подпись); например:control.Invoke((MethodInvoker) delegate {this.Text = "Hi";});Если вам нужно передать параметры, то "захваченные переменные" - это так:
string message = "Hi"; control.Invoke((MethodInvoker) delegate {this.Text = message;});(предостережение: вы должны быть немного осторожны при использовании захватов асинхронные, а синхронизация это нормально - т. е. выше это нормально)
другой вариант-написать метод расширения:
public static void Invoke(this Control control, Action action) { control.Invoke((Delegate)action); }затем:
this.Invoke(delegate { this.Text = "hi"; }); // or since we are using C# 3.0 this.Invoke(() => { this.Text = "hi"; });вы, конечно, можете сделать то же самое с
BeginInvoke:public static void BeginInvoke(this Control control, Action action) { control.BeginInvoke((Delegate)action); }если вы не можете использовать C# 3.0, вы можете сделать то же самое с обычным методом экземпляра, предположительно в
Formбазового класса.
на самом деле вам не нужно использовать ключевое слово delegate. Просто передайте лямбда в качестве параметра:
control.Invoke((MethodInvoker)(() => {this.Text = "Hi"; }));
необходимо создать тип делегата. Ключевое слово "делегат" в создании анонимного метода немного вводит в заблуждение. Вы создаете не анонимный делегат, а анонимный метод. Метод, который вы создали могут быть использованы в делегат. Вот так:
myControl.Invoke(new MethodInvoker(delegate() { (MyMethod(this, new MyEventArgs(someParameter)); }));
для полноты, это также может быть достигнуто с помощью комбинации метода действия / анонимного метода:
//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(); });
У меня были проблемы с другими предложениями, потому что я хочу иногда вернуть ценности из моих методов. Если вы пытаетесь использовать MethodInvoker с возвращаемыми значениями, похоже, это не нравится. Поэтому решение, которое я использую, похоже на это (очень рад услышать способ сделать это более кратким - я использую 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; })); }
Я никогда не понимал, почему это имеет значение для компилятора, но этого достаточно.
public static class ControlExtensions { public static void Invoke(this Control control, Action action) { control.Invoke(action); } }бонус: добавить обработку ошибок, потому что вполне вероятно, что, если вы используете
Control.Invokeиз фонового потока вы обновляете текст / прогресс / включенное состояние элемента управления и не заботитесь о том, что элемент управления уже удален.public static class ControlExtensions { public static void Invoke(this Control control, Action action) { try { if (!control.IsDisposed) control.Invoke(action); } catch (ObjectDisposedException) { } } }
Comments