DispatcherQueue

Hoogtepunten

  • De klasse DispatcherQueue in de Windows App SDK beheert een wachtrij met prioriteit waarop de taken voor een thread op seriële wijze worden uitgevoerd.
  • Het biedt een middel voor achtergrondthreads om code uit te voeren op de thread van DispatcherQueue (bijvoorbeeld de UI-thread waar objecten met threadaffiniteit live zijn).
  • De klasse integreert nauwkeurig met willekeurige berichtlussen. Het ondersteunt bijvoorbeeld het algemene Win32-idioom van geneste berichtlussen.
  • De AppWindow-klasse kan worden geïntegreerd met DispatcherQueue, wanneer een DispatcherQueue voor een bepaalde thread wordt afgesloten, worden de AppWindow-exemplaren automatisch vernietigd.
  • Het biedt een middel om een gemachtigde te registreren die wordt aangeroepen wanneer een time-out verloopt.
  • Het biedt gebeurtenissen die onderdelen laten weten wanneer een berichtlus wordt afgesloten en optioneel die afsluiting uitstellen totdat openstaand werk is voltooid. Dat zorgt ervoor dat onderdelen die de DispatcherQueue gebruiken, maar geen eigenaar zijn van de berichtenlus, opschoonwerkzaamheden op de thread kunnen uitvoeren wanneer de lus wordt beëindigd.
  • DispatcherQueue is een thread singleton (er kan maximaal één van deze worden uitgevoerd op een bepaalde thread). Standaard heeft een thread geen DispatcherQueue.
  • Een threadeigenaar kan een DispatcherQueueController maken om de DispatcherQueue voor de thread te initialiseren. Op dat moment heeft elke code toegang tot de DispatcherQueue van de thread; maar alleen de eigenaar van DispatcherQueueController heeft toegang tot de methode DispatcherQueueController.ShutdownQueue , die de DispatcherQueue leeglaat en afsluitstart- en ShutdownCompleted-gebeurtenissen genereert.
  • De eigenaar van een buitenste berichtenlus moet een DispatcherQueue-exemplaar maken. Alleen de code die verantwoordelijk is voor het uitvoeren van de buitenste berichtlus van een thread weet wanneer de verzending is voltooid. Dit is de juiste tijd om de DispatcherQueue af te sluiten. Dat betekent dat onderdelen die afhankelijk zijn van DispatcherQueue , de DispatcherQueue niet mogen maken, tenzij ze eigenaar zijn van de berichtenlus van de thread.

Overzicht

Nadat een thread de gebeurtenislus heeft afgesloten, moet deze de DispatcherQueue afsluiten. Als u dit doet, worden de gebeurtenissen ShutdownStarting en ShutdownCompleted gegenereerd en worden alle definitief in behandeling zijnde items leeggezogen voordat verdere enqueuing wordt uitgeschakeld.

  • Als u een DispatcherQueue wilt afsluiten die wordt uitgevoerd op een toegewezen thread met een dispatcherQueue-berichtenlus, roept u de methode DispatcherQueueController.ShutdownQueueAsync aan.
  • Voor scenario's waarin de app eigenaar is van een willekeurige berichtlus (bijvoorbeeld XAML-eilanden), roept u de synchrone DispatcherQueueController.ShutdownQueue-methode aan. Die methode genereert shutdown-gebeurtenissen en maakt de DispatcherQueue synchroon leeg op de aanroepende thread.

Wanneer u DispatcherQueueController.ShutdownQueueAsync of DispatcherQueueController.ShutdownQueue aanroept, is de volgorde van de gegenereerde gebeurtenissen het volgende:

  • ShutdownStarting. Bedoeld om door apps te worden afgehandeld.
  • FrameworkShutdownStarting. Bedoeld voor frameworks die moeten worden verwerkt.
  • FrameworkShutdownCompleted. Bedoeld voor frameworks die moeten worden verwerkt.
  • ShutdownCompleted. Bedoeld om door apps te worden afgehandeld.

De gebeurtenissen worden onderverdeeld in toepassings-/frameworkcategorieën, zodat ordelijk afsluiten kan worden bereikt. Dat wil zeggen: door het afsluitsignaal van de toepassing expliciet af te geven voordat de afsluitgebeurtenissen van het framework plaatsvinden, bestaat niet het risico dat een frameworkonderdeel in een onbruikbare toestand terechtkomt terwijl de toepassing wordt afgesloten.

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

Uiterste en recursieve berichtlussen

DispatcherQueue ondersteunt aangepaste berichtlussen. Voor eenvoudige apps die geen aanpassing nodig hebben, bieden we echter een standaard implementatie. Dat neemt ontwikkelaars een last uit handen en helpt consistent correct gedrag te waarborgen.

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

Systeemzenderbeheer

Sommige Windows App SDK-onderdelen (bijvoorbeeld MicaController) zijn afhankelijk van systeemonderdelen die op hun beurt vereisen dat een systeem-DispatcherQueue (Windows.System.DispatcherQueue) op de thread wordt uitgevoerd.

In die gevallen roept het onderdeel met een systeem-DispatcherQueue-afhankelijkheid de methode EnsureSystemDispatcherQueue aan, waardoor uw app geen systeem dispatcherQueue kan beheren.

Wanneer die methode is aangeroepen, beheert de Windows App SDK DispatcherQueue automatisch de levensduur van de systeem-DispatcherQueue, waarbij de systeem-DispatcherQueue samen met de Windows App SDK DispatcherQueue wordt afgesloten. Onderdelen kunnen afhankelijk zijn van zowel Windows App SDK als systeem DispatcherQueue afsluitgebeurtenissen om ervoor te zorgen dat ze de juiste opschoning uitvoeren nadat de berichtlus is afgesloten.

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-integratie

De AppWindow-klasse heeft functionaliteit die deze integreert met de DispatcherQueue, zodat AppWindow-objecten automatisch kunnen worden vernietigd wanneer de methode DispatcherQueueController.ShutdownQueueAsync of DispatcherQueueController.ShutdownQueue wordt aangeroepen.

Er is ook een eigenschap van AppWindow waarmee aanroepers de DispatcherQueue kunnen ophalen die is gekoppeld aan de AppWindow; daarmee wordt deze in overeenstemming gebracht met andere objecten in de naamruimten Composition en Input.

AppWindow heeft uw expliciete aanmelding nodig om op de hoogte te zijn van de 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();
}

Zie ook