Kann jemand bitte diese Aussage auf diesem Link erklären
Invoke(Delegate):
Führt den angegebenen Delegaten in dem Thread aus, dem das zugrunde liegende Fensterhandle des Steuerelements gehört.
Kann jemand erklären, was dies bedeutet (besonders die kühne)? Ich kann es nicht klar verstehen
Antworten:
Die Antwort auf diese Frage liegt in der Funktionsweise von C # Controls
Von Control.InvokeRequired
Tatsächlich stellt Invoke sicher, dass der von Ihnen aufgerufene Code in dem Thread vorkommt, in dem das Steuerelement "lebt", und verhindert effektiv Thread-übergreifende Ausnahmen.
Aus historischer Sicht war dies in .Net 1.1 tatsächlich zulässig. Was es bedeutete, war, dass Sie versuchen konnten, Code auf dem "GUI" -Thread von jedem Hintergrund-Thread aus auszuführen, und dies würde meistens funktionieren. Manchmal wurde Ihre App einfach beendet, weil Sie den GUI-Thread effektiv unterbrochen haben, während er etwas anderes tat. Dies ist die Cross-Threaded-Ausnahme. Stellen Sie sich vor, Sie versuchen, eine TextBox zu aktualisieren, während die GUI etwas anderes malt.
Tatsächlich unterbrechen Sie eine Warteschlange, was viele unvorhergesehene Folgen haben kann. Invoke ist praktisch die "höfliche" Methode, um das, was Sie tun möchten, in diese Warteschlange zu bringen. Diese Regel wurde ab .NET 2.0 über eine ausgelöste InvalidOperationException erzwungen .
Um zu verstehen, was sich tatsächlich hinter den Kulissen abspielt und was unter "GUI-Thread" zu verstehen ist, ist es hilfreich zu verstehen, was eine Nachrichtenpumpe oder eine Nachrichtenschleife ist.
Dies wird bereits in der Frage " Was ist eine Nachrichtenpumpe? " Beantwortet. Es wird empfohlen, diese zu lesen, um den tatsächlichen Mechanismus zu verstehen, an den Sie bei der Interaktion mit Steuerelementen gebunden sind.
Andere Lektüre, die Sie vielleicht nützlich finden, umfasst:
Was ist los mit Begin Invoke?
und für eine codeübergreifendere Übersicht mit einem repräsentativen Beispiel:
Ungültige Cross-Thread-Operationen
Sobald Sie eine Wertschätzung für InvokeRequired haben, können Sie eine Erweiterungsmethode zum Abschluss dieser Aufrufe in Betracht ziehen. Dies wird in der Frage zum Stapelüberlauf ausführlich behandelt . Bereinigen von Code, der mit Invoke Required übersät ist .
Es gibt auch eine weitere Beschreibung dessen, was historisch passiert ist und was von Interesse sein könnte.
quelle
Ein Steuerelement oder Fensterobjekt in Windows Forms ist nur ein Wrapper um ein Win32-Fenster, das durch ein Handle (manchmal auch als HWND bezeichnet) gekennzeichnet ist. Die meisten Dinge, die Sie mit dem Steuerelement tun, führen schließlich zu einem Win32-API-Aufruf, der dieses Handle verwendet. Das Handle gehört dem Thread, der es erstellt hat (normalerweise der Hauptthread) und sollte nicht von einem anderen Thread bearbeitet werden. Wenn Sie aus irgendeinem Grund etwas mit dem Steuerelement eines anderen Threads tun müssen, können Sie
Invoke
den Hauptthread bitten, dies in Ihrem Namen zu tun.Wenn Sie beispielsweise den Text einer Beschriftung aus einem Arbeitsthread ändern möchten, können Sie Folgendes tun:
quelle
this.Invoke(() => this.Enabled = true);
Was auch immer sich daraufthis
bezieht, ist sicherlich im aktuellen Thread, oder?Wenn Sie ein Steuerelement ändern möchten, muss dies in dem Thread erfolgen, in dem das Steuerelement erstellt wurde. Mit dieser
Invoke
Methode können Sie Methoden im zugeordneten Thread ausführen (dem Thread, dem das zugrunde liegende Fensterhandle des Steuerelements gehört).Im folgenden Beispiel löst thread1 eine Ausnahme aus, da SetText1 versucht, textBox1.Text aus einem anderen Thread zu ändern. In Thread2 wird die Aktion in SetText2 jedoch in dem Thread ausgeführt, in dem die TextBox erstellt wurde
quelle
quelle
In der Praxis bedeutet dies, dass der Delegat garantiert im Hauptthread aufgerufen wird. Dies ist wichtig, da bei Windows-Steuerelementen die Änderung entweder nicht angezeigt wird oder das Steuerelement eine Ausnahme auslöst, wenn Sie deren Eigenschaften im Hauptthread nicht aktualisieren.
Das Muster ist:
quelle
this.Invoke(delegate)
Stellen Sie sicher, dass Sie den Delegaten aufrufen, an den das Argumentthis.Invoke()
im Hauptthread / erstellten Thread gesendet wird.Ich kann sagen, dass eine Thumb-Regel nur vom Haupt-Thread aus auf Ihre Formularsteuerelemente zugreift.
Möglicherweise sind die folgenden Zeilen für die Verwendung von Invoke () sinnvoll.
Es gibt Situationen, in denen Sie einen Threadpool-Thread (dh einen Arbeitsthread) erstellen, der auf dem Hauptthread ausgeführt wird. Es wird kein neuer Thread erstellt, da der Haupt-Thread für die Verarbeitung weiterer Anweisungen verfügbar ist. Untersuchen Sie zunächst, ob der aktuell ausgeführte Thread ein Hauptthread ist. Verwenden Sie dazu,
this.InvokeRequired
wenn true zurückgegeben wird. Der aktuelle Code wird im Arbeitsthread ausgeführt. Rufen Sie also this.Invoke (d, new object [] {text}) auf.Andernfalls aktualisieren Sie direkt das UI-Steuerelement (Hier wird garantiert, dass Sie den Code im Hauptthread ausführen.)
quelle
Dies bedeutet, dass der Delegat auf dem UI-Thread ausgeführt wird, selbst wenn Sie diese Methode von einem Hintergrund-Worker oder Thread-Pool-Thread aufrufen. UI-Elemente haben Thread-Affinität - sie sprechen nur gerne direkt mit einem Thread: dem UI-Thread. Der UI-Thread ist definiert als der Thread , der die Steuerinstanz erstellt hat, und ist daher dem Fensterhandle zugeordnet. All dies ist jedoch ein Implementierungsdetail.
Der entscheidende Punkt ist: Sie würden diese Methode von einem Arbeitsthread aus aufrufen, damit Sie auf die Benutzeroberfläche zugreifen können (um den Wert in einer Beschriftung usw. zu ändern), da Sie dies von keinem anderen Thread als dem Benutzeroberflächenthread aus tun dürfen .
quelle
Delegierte sind im Wesentlichen Inline
Action
oderFunc<T>
. Sie können einen Delegaten außerhalb des Bereichs einer Methode deklarieren, die Sie ausführen oder die einenlambda
Ausdruck (=>
) verwendet. Da Sie den Delegaten innerhalb einer Methode ausführen, führen Sie ihn auf dem Thread aus, der für das aktuelle Fenster / die aktuelle Anwendung ausgeführt wird.Lambda Beispiel
quelle
Dies bedeutet, dass der von Ihnen übergebene Delegat in dem Thread ausgeführt wird, der das Control-Objekt erstellt hat (dies ist der UI-Thread).
Sie müssen diese Methode aufrufen, wenn Ihre Anwendung über mehrere Threads verfügt und Sie eine UI-Operation von einem anderen Thread als dem UI-Thread ausführen möchten. Wenn Sie nur versuchen, eine Methode für ein Steuerelement von einem anderen Thread aus aufzurufen, erhalten Sie eine System.InvalidOperationException.
quelle