Dispatcher.CurrentDispatcher vs. Application.Current.Dispatcher

78

Was sind die Unterschiede zwischen Dispatcher.CurrentDispatcher(in System.Windows.Threading) und Application.Current.Dispatcher(in System.Windows)?

Mein Bauch sagt mir, dass sich Application.Current.Dispatcherdas nie ändern wird und für alle Threads in der aktuellen Anwendung global ist, während abhängig vom Thread, von dem es aufgerufen wurde , Dispatcher.CurrentDispatchermöglicherweise eine neue Instanz erstellt wird Dispatcher.

Ist das korrekt?

Wenn ja, ist der Zweck in Dispatcher.CurrentDispatchererster Linie für die Multithread-Benutzeroberfläche?

Ken
quelle

Antworten:

98

Mein Bauch sagt mir, dass sich Application.Current.Dispatcher niemals ändern wird und für alle Threads in der aktuellen Anwendung global ist, während Dispatcher.CurrentDispatcher abhängig vom Thread, von dem es aufgerufen wurde, möglicherweise eine neue Instanz von Dispatcher erstellt.

Das ist richtig.

Darüber hinaus macht es überhaupt keinen Sinn, Dispatcher.CurrentDispatchervon einem Nicht-UI-Thread aus zuzugreifen . Es wird nichts tun, es sei denn, Sie rufen an Dispatcher.Run, und in eine Endlos-Nachrichtenschleife zu gehen, ist nicht das, was Sie in Worker-Threads tun möchten.

Damit:

  • Im häufigsten Szenario , in dem Ihre App nur einen einzigen UI-Thread hat Application.Current.Dispatcherund Dispatcher.CurrentDispatcherinnerhalb des UI-Threads dieselbe Instanz zurückgibt. Welches Sie verwenden, ist einfach eine Frage der Präferenz.

  • Wenn Ihre App mehr als einen UI-Thread hat, wird jeder DispatcherObjectpermanent dem Dispatcher des UI-Threads zugeordnet, in dem er bei der Erstellung erstellt wurde. In diesem Fall Application.Current.Dispatcherwird auf den Dispatcher des Threads verwiesen, mit dem Ihre Anwendung erstellt wurde. Sie können damit keine Nachrichten an Steuerelemente senden, die Ihren anderen UI-Threads gehören.

Jon
quelle
2
Vielen Dank für die Erklärung, aber was meinen Sie mit "Es wird nichts tun, wenn Sie nicht Dispatcher.Run anrufen"? Ich habe CurrentDispatcher aus einem Nicht-UI-Thread verwendet, und Invoke ruft tatsächlich einen Delegaten auf. Meinen Sie damit, dass die Delegaten einfach im aufrufenden Thread aufgerufen werden?
Ken
2
@ken: Invokeund Freunde "verpacken" normalerweise (Marschall, wenn Sie es vorziehen) einen Methodenaufruf in eine Win32-Nachricht und stellen ihn in eine Nachrichtenwarteschlange, aus der eine Nachrichtenschleife (die Dispatcher-Schleife) sie schließlich extrahiert und den Aufruf ausführt. Da es keine Dispatcher-Schleife gibt (wenn Sie in dieser Schleife wären, würde Ihr Code nicht ausgeführt), würde der Aufruf niemals tatsächlich stattfinden. Ich gehe also davon aus, dass Invokezunächst geprüft wird, ob Sie sich bereits CurrentDispatcherals Optimierung im Thread befinden und ob Sie den Aufruf vor Ort ausführen, anstatt ihn zu marshallen. Sie können dies überprüfen, indem Sie überprüfen Thread.ManagedThreadId.
Jon
Sie können damit keine Nachrichten an Steuerelemente senden, die Ihren anderen UI-Threads gehören. Wie viele UI-Threads enthält Ihre durchschnittliche WPF-Anwendung?
@ Will: Eins: "Wenn Ihre App nur einen UI-Thread hat (höchstwahrscheinlich) ..." . Denken Sie, dass es mehr Klarheit braucht?
Jon
1
@ Will: Bearbeitet, um die Sichtbarkeit des relevanten Teils zu erhöhen. Danke für die Information.
Jon
21

Einfach gesagt...

Dispatcher.CurrentDispatcherRuft den Dispatcher für den aktuellen Thread ab . Wenn Sie also über einen Hintergrundprozess nach dem Dispatcher des UI-Threads suchen, verwenden Sie diesen nicht.

Application.Current.Dispatcher gibt Ihnen immer den Dispatcher des UI-Threads, da dies der Thread ist, der die einzige Anwendungsinstanz hochfährt.


quelle
9

Mein Bauch sagt mir, dass sich Application.Current.Dispatcher niemals ändern wird und für alle Threads in der aktuellen Anwendung global ist, während Dispatcher.CurrentDispatcher abhängig vom Thread, von dem es aufgerufen wurde, möglicherweise eine neue Instanz von Dispatcher erstellt.

Das ist richtig, das Application.Current.Dispatcherist eine Instanzeigenschaft der Anwendung, die bei der Erstellung als Dispatcher des aktuellen Threads zugewiesen wird. Und wie die Dokumentation von Dispatcher.CurrentDispatcherzeigt:

Ruft den Dispatcher für den aktuell ausgeführten Thread ab und erstellt einen neuen Dispatcher, falls dem Thread noch keiner zugeordnet ist.


Wenn ja, ist der Zweck von Dispatcher.CurrentDispatcher hauptsächlich für die Multithread-Benutzeroberfläche?

Möglicherweise habe ich keine Verwendung gefunden, um den Dispatcher eines Hintergrund-Threads zu erhalten, da Sie normalerweise keine dazugehörigen UI-Elemente haben, zu denen Sie möglicherweise Operationen versenden möchten.

HB
quelle