Ponieważ Invoke
/ BeginInvoke
accepts Delegate
(zamiast delegata o określonym typie), musisz powiedzieć kompilatorowi, jaki typ delegata ma utworzyć; MethodInvoker
(2.0) lub Action
(3.5) to typowe wybory (zauważ, że mają ten sam podpis); tak:
control.Invoke((MethodInvoker) delegate {this.Text = "Hi";});
Jeśli chcesz przekazać parametry, sposobem na to są „przechwycone zmienne”:
string message = "Hi";
control.Invoke((MethodInvoker) delegate {this.Text = message;});
(uwaga: musisz być nieco ostrożny, jeśli używasz przechwytywania asynchronicznego , ale synchronizacja jest w porządku - tj. powyższe jest w porządku)
Inną opcją jest napisanie metody rozszerzającej:
public static void Invoke(this Control control, Action action)
{
control.Invoke((Delegate)action);
}
następnie:
this.Invoke(delegate { this.Text = "hi"; });
this.Invoke(() => { this.Text = "hi"; });
Możesz oczywiście zrobić to samo z BeginInvoke
:
public static void BeginInvoke(this Control control, Action action)
{
control.BeginInvoke((Delegate)action);
}
Jeśli nie możesz użyć języka C # 3.0, możesz zrobić to samo ze zwykłą metodą wystąpienia, prawdopodobnie w Form
klasie bazowej.
Form.Load += Loader()
zamiast staregoForm.Load += new EventHandler(Loader())
Właściwie nie musisz używać słowa kluczowego delegate. Po prostu podaj lambdę jako parametr:
control.Invoke((MethodInvoker)(() => {this.Text = "Hi"; }));
źródło
myControl.Invoke(new MethodInvoker(delegate() {...}))
źródło
Musisz utworzyć typ pełnomocnika. Słowo kluczowe „delegat” w tworzeniu anonimowych metod jest nieco mylące. Nie tworzysz anonimowego delegata, ale anonimową metodę. Utworzonej metody można użyć w delegacie. Lubię to:
myControl.Invoke(new MethodInvoker(delegate() { (MyMethod(this, new MyEventArgs(someParameter)); }));
źródło
Ze względu na kompletność można to również osiągnąć za pomocą kombinacji Metoda działania / metoda anonimowa:
//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(); });
źródło
Invoke((Action) Process);
to najlepsza odpowiedź, dziękuję!Miałem problemy z innymi sugestiami, ponieważ czasami chcę zwrócić wartości z moich metod. Jeśli spróbujesz użyć MethodInvoker ze zwracanymi wartościami, nie wydaje się to podoba. Więc rozwiązanie, którego używam, jest takie (bardzo miło słyszę, jak to zrobić bardziej zwięźle - używam 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; })); }
źródło
Lubię używać Action zamiast MethodInvoker, jest krótszy i wygląda czysto.
Invoke((Action)(() => { DoSomething(); })); // OR Invoke((Action)delegate { DoSomething(); });
Na przykład.
// 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"; }
źródło
Nigdy nie rozumiałem, dlaczego ma to znaczenie dla kompilatora, ale to wystarczy.
public static class ControlExtensions { public static void Invoke(this Control control, Action action) { control.Invoke(action); } }
Bonus: dodaj obsługę błędów, ponieważ jest prawdopodobne, że jeśli używasz
Control.Invoke
z wątku w tle, aktualizujesz stan tekstu / postępu / włączenia kontrolki i nie obchodzi Cię, czy formant jest już usunięty.public static class ControlExtensions { public static void Invoke(this Control control, Action action) { try { if (!control.IsDisposed) control.Invoke(action); } catch (ObjectDisposedException) { } } }
źródło