DispatcherQueue

Nejzajímavější body

  • Třída DispatcherQueue v Windows App SDK spravuje prioritní frontu, na které se úlohy vlákna spouští sériově.
  • Umožňuje vláknům na pozadí spouštět kód ve vlákně fronty DispatcherQueue (například ve vlákně uživatelského rozhraní, kde se nacházejí objekty vázané na konkrétní vlákno).
  • Třídu lze přesně integrovat s libovolnými smyčkami zpráv. Podporuje například běžný idiom Win32 vnořených smyček zpráv.
  • Třída AppWindow se integruje s DispatcherQueue – když dispatcherQueue pro dané vlákno je vypnuto, instance AppWindow jsou automaticky zničeny.
  • Umožňuje zaregistrovat delegáta, který je vyvolán po vypršení časového limitu.
  • Poskytuje události, které informují komponenty o tom, že se smyčka zpráv ukončuje, a volitelně toto ukončení odloží, dokud nebudou dokončeny zbývající úlohy. Tím se zajistí, že komponenty, které používají DispatcherQueue, ale nevlastní smyčku zpráv, můžou při ukončení smyčky provádět čištění vlákna.
  • DispatcherQueue je jednovláknové vlákno (na libovolném vlákně může běžet maximálně jeden z nich). Ve výchozím nastavení vlákno nemá žádnou DispatcherQueue.
  • Vlastník vlákna může vytvořit DispatcherQueueController k inicializaci DispatcherQueue pro dané vlákno. V tomto okamžiku může jakýkoli kód přistupovat k objektu DispatcherQueue daného vlákna; ale pouze vlastník objektu DispatcherQueueController má přístup k metodě DispatcherQueueController.ShutdownQueue, která vyčerpá objekt DispatcherQueue a vyvolá události ShutdownStarting a ShutdownCompleted.
  • Vnější vlastník smyčky zpráv musí vytvořit instanci DispatcherQueue . Pouze kód, který je zodpovědný za spuštění vnější smyčky zpráv vlákna, ví, kdy je odeslání dokončeno, což je vhodná doba pro vypnutí DispatcherQueue. To znamená, že komponenty, které závisejí na DispatcherQueue, nesmějí vytvořit DispatcherQueue, pokud nevlastní smyčku zpráv daného vlákna.

Přehled

Jakmile vlákno ukončí smyčku událostí, musí ukončit svou DispatcherQueue. Tím dojde k vyvolání událostí ShutdownStarting a ShutdownCompleted a ke zpracování všech zbývajících čekajících položek ve frontě před zakázáním dalšího přidávání do fronty.

  • Chcete-li vypnout DispatcherQueue, která běží na vyhrazeném vlákně se smyčkou zpráv ve vlastnictví DispatcherQueue, zavolejte metodu DispatcherQueueController.ShutdownQueueAsync.
  • Ve scénářích, ve kterých aplikace vlastní libovolnou smyčku zpráv (například ostrovy XAML), volejte synchronní metodu DispatcherQueueController.ShutdownQueue . Tato metoda vyvolá události vypnutí a vyprázdní DispatcherQueue synchronně na volající vlákno.

Když zavoláte buď DispatcherQueueController.ShutdownQueueAsync, nebo DispatcherQueueController.ShutdownQueue, pořadí vyvolání událostí je následující:

  • ShutdownStarting. Určeno pro to, aby to zpracovávaly aplikace.
  • FrameworkShutdownStarting. Určeno pro frameworky ke zpracování.
  • FrameworkShutdownCompleted. Určeno pro frameworky ke zpracování.
  • ShutdownCompleted. Určeno pro to, aby to zpracovávaly aplikace.

Události jsou rozdělené do kategorií aplikace/architektury, aby bylo možné dosáhnout seřazeného vypnutí. To znamená, že tím, že se explicitně vyvolá ukončení aplikace před událostmi vypnutí frameworku, nehrozí, že komponenta frameworku bude během ukončování aplikace v nepoužitelném stavu.

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))
        {
            TranslateMessage(&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();
}

Nejvnější a rekurzivní smyčky zpráv

DispatcherQueue podporuje vlastní smyčky zpráv. U jednoduchých aplikací, které nepotřebují přizpůsobení, ale poskytujeme výchozí implementaci. Tím se vývojářům eliminuje zátěž a pomáhá zajistit konzistentní správné chování.

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();
}

Správa dispečera systému

Některé komponenty sady Windows App SDK (například MicaController) závisejí na systémových komponentách, které zase vyžadují, aby ve vlákně běžela systémová DispatcherQueue (Windows.System.DispatcherQueue).

V takových případech komponenta, která závisí na systémové frontě DispatcherQueue, volá metodu EnsureSystemDispatcherQueue, takže vaše aplikace nemusí spravovat systémovou frontu DispatcherQueue.

Po volání této metody Windows App SDK DispatcherQueue automaticky spravuje životní cyklus systémové fronty DispatcherQueue a ukončí systémovou frontu DispatcherQueue spolu s Windows App SDK DispatcherQueue. Komponenty můžou záviset na událostech vypnutí Windows App SDK i systému DispatcherQueue, aby se zajistilo správné vyčištění po ukončení smyčky zpráv.

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();
}

Integrace AppWindow

AppWindow třída má funkce, které ji integruje s DispatcherQueue, takže AppWindow objekty lze automaticky zničit, když DispatcherQueueController.ShutdownQueueAsync nebo DispatcherQueueController.ShutdownQueue metoda je volána.

Existuje také vlastnost AppWindow, která volajícím umožňuje získat instanci DispatcherQueue přidruženou k AppWindow, čímž se sjednocuje s ostatními objekty v oborech názvů Composition a Input.

AppWindow potřebuje vaše explicitní vyjádření souhlasu, aby bylo možné znát DispatcherQueue.

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()};

    auto appWindow = AppWindow::Create(nullptr, 0, dispatcherQueueController.DispatcherQueue());

    // Since we associated the DispatcherQueue above with the AppWindow, we're able to retrieve 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.Destroyed
    // event will be raised since the AppWindow instance is associated with the DispatcherQueue.
    dispatcherQueueController.ShutdownQueue();
}

Viz také