Mir ist schmerzlich bewusst geworden, wie oft man das folgende Codemuster in ereignisgesteuerten GUI-Code schreiben muss, wo
private void DoGUISwitch() {
// cruisin for a bruisin' through exception city
object1.Visible = true;
object2.Visible = false;
}
wird:
private void DoGUISwitch() {
if (object1.InvokeRequired) {
object1.Invoke(new MethodInvoker(() => { DoGUISwitch(); }));
} else {
object1.Visible = true;
object2.Visible = false;
}
}
Dies ist ein umständliches Muster in C #, sowohl zum Erinnern als auch zum Tippen. Hat jemand eine Verknüpfung oder ein Konstrukt entwickelt, das dies bis zu einem gewissen Grad automatisiert? Es wäre cool, wenn es eine Möglichkeit gäbe, Objekten, die diese Prüfung durchführen, eine Funktion zuzuweisen, ohne all diese zusätzlichen Arbeiten wie eine object1.InvokeIfNecessary.visible = true
Typverknüpfung ausführen zu müssen.
In früheren Antworten wurde die Unpraktikabilität diskutiert, jedes Mal nur Invoke () aufzurufen, und selbst dann ist die Invoke () -Syntax sowohl ineffizient als auch immer noch umständlich zu handhaben.
Hat jemand irgendwelche Abkürzungen herausgefunden?
quelle
object1.InvokeIfNecessary.Visible = true
Linie inspiriert ist. Schauen Sie sich meine aktualisierte Antwort an und teilen Sie mir Ihre Meinung mit.Antworten:
Lees Ansatz kann weiter vereinfacht werden
Und kann so genannt werden
Es ist nicht erforderlich, das Steuerelement als Parameter an den Delegaten zu übergeben. C # erstellt automatisch einen Abschluss .
UPDATE :
Nach mehreren anderen Postern
Control
kann verallgemeinert werden alsISynchronizeInvoke
:DonBoitnott wies darauf hin, dass im Gegensatz
Control
zurISynchronizeInvoke
Schnittstelle ein Objektarray für dieInvoke
Methode als Parameterliste für die erforderlich istaction
.UPDATE 2
Von Mike de Klerk vorgeschlagene Änderungen (Einfügungspunkt siehe Kommentar im 1. Codeausschnitt):
Weitere Informationen zu diesem Vorschlag finden Sie im Kommentar von ToolmakerSteve.
quelle
ISynchronizeInvoke
stattControl
? (Ein großesISynchronizeInvoke
. Aber der einzige Typ, der sich daraus ableitet (laut Reflector), istControl
, so dass der Vorteil begrenzt ist.while (!control.Visible) ..sleep..
. Für mich hat das einen schlechten Code-Geruch, da es sich um eine möglicherweise unbegrenzte Verzögerung handelt (in einigen Fällen sogar um eine Endlosschleife), in Code, der möglicherweise Anrufer enthält, die keine solche Verzögerung (oder sogar einen Deadlock) erwarten. IMHO, jede Verwendung vonSleep
sollte in der Verantwortung jedes Anrufers liegen, ODER sollte in einem separaten Wrapper sein, der klar in Bezug auf seine Konsequenzen gekennzeichnet ist. IMHO, normalerweise ist es besser, "hart zu versagen" (Ausnahme, während des Testens zu fangen) oder "nichts zu tun", wenn die Steuerung nicht bereit ist. Bemerkungen?InvokeRequired
Gibt an, ob sich der aufrufende Thread von dem Thread unterscheidet, der das Steuerelement erstellt hat.Invoke
Übergibt die Aktion vom aufrufenden Thread an den Thread des Steuerelements, in dem sie ausgeführt wird. Dies stellt sicher, dass beispielsweise ein Klickereignishandler niemals unterbrochen wird.Sie könnten eine Erweiterungsmethode schreiben:
Und benutze es so:
BEARBEITEN: Wie Simpzon in den Kommentaren hervorhebt, können Sie die Signatur auch ändern in:
quelle
Hier ist das Formular, das ich in meinem gesamten Code verwendet habe.
Ich habe dies auf dem Blogeintrag hier basiert . Ich habe diesen Ansatz nicht verfehlt, daher sehe ich keinen Grund, meinen Code mit einer Überprüfung der zu komplizieren
InvokeRequired
Eigenschaft .Hoffe das hilft.
quelle
InvokeRequired
wenn der Code ausgeführt werden konnte, bevor das Steuerelement angezeigt wurde, oder Sie haben eine schwerwiegende Ausnahme.Erstellen Sie eine ThreadSafeInvoke.snippet-Datei, und wählen Sie dann einfach die Update-Anweisungen aus, klicken Sie mit der rechten Maustaste und wählen Sie "Surround With ..." oder Strg-K + S:
quelle
Hier ist eine verbesserte / kombinierte Version der Antworten von Lee, Oliver und Stephan.
Die Vorlage ermöglicht flexiblen und Cast-freien Code, der viel besser lesbar ist, während der dedizierte Delegat für Effizienz sorgt.
quelle
Ich würde lieber eine einzelne Instanz einer Methode Delegate verwenden, anstatt jedes Mal eine neue Instanz zu erstellen. In meinem Fall habe ich den Fortschritt und (Info- / Fehler-) Meldungen eines Backroundworkers angezeigt, die große Datenmengen von einer SQL-Instanz kopierten und umwandelten. Nach ungefähr 70000 Fortschritten und Nachrichtenaufrufen funktionierte mein Formular nicht mehr und zeigte neue Nachrichten an. Dies trat nicht auf, als ich anfing, einen einzelnen globalen Instanzdelegaten zu verwenden.
quelle
Verwendung:
Code:
quelle
Ich mache es gerne ein bisschen anders, ich nenne es gerne "mich", wenn es nötig ist, mit einer Aktion,
Dies ist ein praktisches Muster. Das IsFormClosing ist ein Feld, das ich beim Schließen meines Formulars auf True gesetzt habe, da möglicherweise noch einige Hintergrundthreads ausgeführt werden ...
quelle
Sie sollten niemals Code schreiben, der so aussieht:
Wenn Sie Code haben, der so aussieht, ist Ihre Anwendung nicht threadsicher. Dies bedeutet, dass Sie Code haben, der DoGUISwitch () bereits von einem anderen Thread aus aufruft. Es ist zu spät, um zu überprüfen, ob es sich um einen anderen Thread handelt. InvokeRequire muss aufgerufen werden, BEVOR Sie DoGUISwitch anrufen. Sie sollten nicht von einem anderen Thread aus auf eine Methode oder Eigenschaft zugreifen.
Referenz: Control.InvokeRequired-Eigenschaft, in der Sie Folgendes lesen können:
In einer einzelnen CPU-Architektur gibt es kein Problem, aber in einer Architektur mit mehreren CPUs kann ein Teil des UI-Threads dem Prozessor zugewiesen werden, auf dem der aufrufende Code ausgeführt wurde ... und wenn sich dieser Prozessor von dem des UI-Threads unterscheidet wurde dann ausgeführt, wenn der aufrufende Thread beendet wird Windows wird denken, dass der UI-Thread beendet wurde und den Anwendungsprozess beenden, dh Ihre Anwendung wird ohne Fehler beendet.
quelle
invoke()
et al., Bevor das Steuerelement ein Handle erhält, aber IMHO beschreibt nicht, was Sie beschrieben haben. Der springende Punkt bei all dieseminvoke()
Unsinn ist, die Benutzeroberfläche threadsicher zu aktualisieren, und ich würde denken, dass das Platzieren weiterer Anweisungen in einem blockierenden Kontext zu Stottern führen würde. (Ugh ... froh, dass ich aufgehört habe, M $ tech zu verwenden. So kompliziert!)