DispatcherQueue
Highlights
- Die DispatcherQueue-Klasse im Windows App SDK verwaltet eine priorisierte Warteschlange, in der die Aufgaben für einen Thread serial ausgeführt werden.
- Sie stellt eine Möglichkeit für Hintergrundthreads zum Ausführen von Code im Thread eines DispatcherQueue bereit (z. B. der UI-Thread, in dem Objekte mit Threadaffinität live sind).
- Die Klasse lässt sich präzise in beliebige Nachrichtenschleifen integrieren. Sie unterstützt z. B. das allgemeine Win32-Idiom geschachtelter Nachrichtenschleifen.
- Die AppWindow-Klasse wird in DispatcherQueue integriert– wenn ein DispatcherQueue für einen bestimmten Thread heruntergefahren wird, werden die AppWindow-Instanzen automatisch zerstört.
- Sie bietet eine Möglichkeit zum Registrieren einer Stellvertretung, die aufgerufen wird, wenn ein Timeout abläuft.
- Es stellt Ereignisse bereit, die Komponenten darüber informieren, wann eine Nachrichtenschleife beendet wird, und optional das Herunterfahren zurückstellen, bis die ausstehende Arbeit abgeschlossen ist. Dadurch wird sichergestellt, dass Komponenten, die die DispatcherQueue verwenden, aber nicht die Nachrichtenschleife besitzen, beim Beenden der Schleife bereinigt werden.
- " DispatcherQueue " ist ein Thread-Singleton (es kann höchstens ein Thread-Singleton vorhanden sein, der auf einem beliebigen Thread ausgeführt wird). Standardmäßig weist ein Thread keine DispatcherQueue auf.
- Ein Threadbesitzer kann einen DispatcherQueueController erstellen, um den DispatcherQueue für den Thread zu initialisieren. Zu diesem Zeitpunkt kann jeder Code auf die DispatcherQueue des Threads zugreifen. Aber nur der Besitzer des DispatcherQueueControllers hat Zugriff auf die DispatcherQueueController.ShutdownQueue-Methode, die den DispatcherQueue entwässert, und löst ShutdownStarted- und ShutdownCompleted-Ereignisse aus.
- Ein äußerster Nachrichtenschleifenbesitzer muss eine DispatcherQueue-Instanz erstellen. Nur der Code, der für die Ausführung der äußersten Nachrichtenschleife eines Threads zuständig ist, weiß, wann die Verteilerschleife abgeschlossen ist, was die geeignete Zeit zum Herunterfahren der DispatcherQueue ist. Das bedeutet, dass Komponenten, die auf DispatcherQueue basieren, nicht die DispatcherQueue erstellen müssen, es sei denn, sie besitzen die Nachrichtenschleife des Threads.
Runtergekommen
Nachdem ein Thread die Ereignisschleife beendet hat, muss er die DispatcherQueue herunterfahren. Dadurch werden die Ereignisse "ShutdownStarting " und "ShutdownCompleted " ausgelöst und alle endgültigen ausstehenden enqueuierten Elemente entwässert, bevor weitere Enqueuing deaktiviert wird.
- Rufen Sie die DispatcherQueue.ShutdownQueue-Methode auf, um eine DispatcherQueue-Schleife zu beenden, die auf einem dedizierten Thread mit einer DispatcherQueue-eigenen Nachrichtenschleife ausgeführt wird.
- Rufen Sie für Szenarien, in denen die App eine beliebige Nachrichtenschleife besitzt (z. B. XAML-Inseln), die synchrone DispatcherQueueController.ShutdownQueue-Methode auf. Diese Methode löst Herunterfahren-Ereignisse aus und entwässert die DispatcherQueue synchron im aufrufenden Thread.
Wenn Sie " DispatcherQueueController.ShutdownQueueAsync " oder "DispatcherQueueController.ShutdownQueue" aufrufen, lautet die Reihenfolge der ausgelösten Ereignisse wie folgt:
- ShutdownStarting. Für Apps vorgesehen, die behandelt werden sollen.
- FrameworkShutdownStarting. Für Frameworks vorgesehen, die behandelt werden sollen.
- FrameworkShutdownCompleted. Für Frameworks vorgesehen, die behandelt werden sollen.
- ShutdownCompleted. Für Apps vorgesehen, die behandelt werden sollen.
Die Ereignisse werden in Anwendungs-/Framework-Kategorien unterteilt, sodass das geordnete Herunterfahren erreicht werden kann. Das heißt, durch explizites Auslösen des Herunterfahrens von Anwendungen vor Framework-Herunterfahren-Ereignissen besteht keine Gefahr, dass eine Frameworkkomponente in einem nicht verwendbaren Zustand ist, wenn die Anwendung abwickelt.
namespace winrt
{
using namespace Microsoft::UI::Dispatching;
}
// App runs its own custom message loop.
void RunCustomMessageLoop()
{
// Create a DispatcherQueue.
auto dispatcherQueueController{winrt::DispatcherQueueController::CreateOnCurrentThread()};
// Run a custom message loop. Runs until the message loop owner decides to stop.
MSG msg;
while (GetMessage(&msg, nullptr, 0, 0))
{
if (!ContentPreTranslateMessage(&msg))
{
TranslateMesasge(&msg);
DispatchMessage(&msg);
}
}
// Run down the DispatcherQueue. This single call also runs down the system DispatcherQueue
// if one was created via EnsureSystemDispatcherQueue:
// 1. Raises DispatcherQueue.ShutdownStarting event.
// 2. Drains remaining items in the DispatcherQueue, waits for deferrals.
// 3. Raises DispatcherQueue.FrameworkShutdownStarting event.
// 4. Drains remaining items in the DispatcherQueue, waits for deferrals.
// 5. Disables further enqueuing.
// 6. Raises the DispatcherQueue.FrameworkShutdownCompleted event.
// 7. Raises the DispatcherQueue.ShutdownCompleted event.
dispatcherQueueController.ShutdownQueue();
}
Äußerste und rekursive Nachrichtenschleifen
DispatcherQueue unterstützt benutzerdefinierte Nachrichtenschleifen. Für einfache Apps, die keine Anpassung benötigen, stellen wir jedoch eine Standardimplementierung bereit. Das entlastet Entwickler und trägt dazu bei, ein konsistentes korrektes Verhalten sicherzustellen.
namespace winrt
{
using namespace Microsoft::UI::Dispatching;
}
// Simple app; doesn't need a custom message loop.
void RunMessageLoop()
{
// Create a DispatcherQueue.
auto dispatcherQueueController{winrt::DispatcherQueueController::CreateOnCurrentThread()};
// Runs a message loop until a call to DispatcherQueue.EnqueueEventLoopExit or PostQuitMessage.
dispatcherQueueController.DispatcherQueue().RunEventLoop();
// Run down the DispatcherQueue.
dispatcherQueueController.ShutdownQueue();
}
// May be called while receiving a message.
void RunNestedLoop(winrt::DispatcherQueue dispatcherQueue)
{
// Runs a message loop until a call to DispatcherQueue.EnqueueEventLoopExit or PostQuitMessage.
dispatcherQueue.RunEventLoop();
}
// Called to break out of the message loop, returning from the RunEventLoop call lower down the
// stack.
void EndMessageLoop(winrt::DispatcherQueue dispatcherQueue)
{
// Alternatively, calling Win32's PostQuitMessage has the same effect.
dispatcherQueue.EnqueueEventLoopExit();
}
Verwaltung von System dispatcher
Einige Komponenten des Windows App SDK (z . B. MicaController) sind von Systemkomponenten abhängig, die wiederum einen System DispatcherQueue (Windows.System.DispatcherQueue) erfordern, der auf dem Thread ausgeführt wird.
In diesen Fällen ruft die Komponente, die über eine SystemverteilerQueue-Abhängigkeit verfügt, die EnsureSystemDispatcherQueue-Methode auf, sodass Ihre App von der Verwaltung eines System DispatcherQueue befreit wird.
Mit dieser aufgerufenen Methode verwaltet das Windows App SDK DispatcherQueue die Lebensdauer des Systems DispatcherQueue automatisch, und das System DispatcherQueue wird zusammen mit dem Windows App SDK DispatcherQueue heruntergefahren. Komponenten verwenden möglicherweise sowohl das Windows App SDK als auch das System DispatcherQueue-Herunterfahren , um sicherzustellen, dass sie nach dem Beenden der Nachrichtenschleife ordnungsgemäß bereinigt werden.
namespace winrt
{
using namespace Microsoft::UI::Composition::SystemBackdrops;
using namespace Microsoft::UI::Dispatching;
}
// The Windows App SDK component calls this during its startup.
void MicaControllerInitialize(winrt::DispatcherQueue dispatcherQueue)
{
dispatcherQueue.EnsureSystemDispatcherQueue();
// If the component needs the system DispatcherQueue explicitly, it can now grab it off the thread.
winrt::Windows::System::DispatcherQueue systemDispatcherQueue =
winrt::Windows::System::DispatcherQueue::GetForCurrentThread();
}
void AppInitialize()
{
// App doesn't need to concern itself with the system DispatcherQueue dependency.
auto micaController = winrt::MicaController();
}
AppWindow-Integration
Die AppWindow-Klasse verfügt über Funktionen, die sie in die DispatcherQueue integrieren, sodass AppWindow-Objekte automatisch zerstört werden können, wenn die DispatcherQueueController.ShutdownQueueAsync - oder DispatcherQueueController.ShutdownQueue-Methode aufgerufen wird.
Es gibt auch eine Eigenschaft von AppWindow , mit der Aufrufer die DispatcherQueue abrufen können, die der AppWindow zugeordnet ist. Sie richtet sie an andere Objekte in den Composition - und Input-Namespaces aus.
AppWindow benötigt Ihre explizite Zustimmung, um die DispatcherQueue zu beachten.
namespace winrt
{
using namespace Microsoft::UI::Dispatching;
using namespace Microsoft::UI::Windowing;
}
void Main()
{
// Create a Windows App SDK DispatcherQueue.
auto dispatcherQueueController{winrt::DispatcherQueueController::CreateOnCurrentThread()};
var appWindow = AppWindow.Create(nullptr, 0, dispatcherQueueController.DispatcherQueue());
// Since we associated the DispatcherQueue above with the AppWindow, we're able to retreive it
// as a property. If we were to not associate a dispatcher, this property would be null.
ASSERT(appWindow.DispatcherQueue() == dispatcherQueueController.DispatcherQueue());
// Runs a message loop until a call to DispatcherQueue.EnqueueEventLoopExit or PostQuitMessage.
dispatcherQueueController.DispatcherQueue().RunEventLoop();
// Rundown the Windows App SDK DispatcherQueue. While this call is in progress, the AppWindow.Destoyed
// event will be raised since the AppWindow instance is associated with the DispatcherQueue.
dispatcherQueueController.ShutdownQueue();
}
Windows developer