Bagikan melalui


DispatcherQueue

Sorotan

  • Kelas DispatcherQueue di SDK Aplikasi Windows mengelola antrean yang diprioritaskan di mana tugas untuk utas dijalankan dengan cara serial.
  • Ini menyediakan sarana bagi utas latar belakang untuk menjalankan kode pada utas DispatcherQueue (misalnya, utas UI tempat objek dengan afinitas utas aktif).
  • Kelas ini justru terintegrasi dengan perulangan pesan arbitrer. Misalnya, ini mendukung idiom Win32 umum dari perulangan pesan berlapis.
  • Kelas AppWindow terintegrasi dengan DispatcherQueue—saat DispatcherQueue untuk utas tertentu dimatikan, instans AppWindow secara otomatis dihancurkan.
  • Ini menyediakan sarana untuk mendaftarkan delegasi yang dipanggil ketika batas waktu berakhir.
  • Ini menyediakan peristiwa yang memberi tahu komponen ketika perulangan pesan keluar, dan secara opsional menunda penonaktifan tersebut hingga pekerjaan yang terutang selesai. Itu memastikan komponen yang menggunakan DispatcherQueue, tetapi tidak memiliki perulangan pesan, dapat melakukan pembersihan pada utas saat loop keluar.
  • DispatcherQueue adalah singleton utas (mungkin ada paling banyak salah satu dari mereka yang berjalan pada utas tertentu). Secara default, utas tidak memiliki DispatcherQueue.
  • Pemilik utas dapat membuat DispatcherQueueController untuk menginisialisasi DispatcherQueue untuk utas. Pada saat itu, kode apa pun dapat mengakses DispatcherQueue utas; tetapi hanya pemilik DispatcherQueueController yang memiliki akses ke metode DispatcherQueueController.ShutdownQueue, yang mengosongkan DispatcherQueue, dan meningkatkan peristiwa ShutdownStarted dan ShutdownCompleted.
  • Pemilik perulangan pesan terluar harus membuat instans DispatcherQueue . Hanya kode yang bertanggung jawab untuk menjalankan perulangan pesan terluar utas yang tahu kapan pengiriman selesai, yang merupakan waktu yang tepat untuk mematikan DispatcherQueue. Itu berarti bahwa komponen yang mengandalkan DispatcherQueue tidak boleh membuat DispatcherQueue kecuali mereka memiliki perulangan pesan utas.

Run-down

Setelah utas keluar dari perulangan peristiwanya, utas harus mematikan DispatcherQueue-nya. Melakukannya meningkatkan peristiwa ShutdownStarting dan ShutdownCompleted , dan menguras item antrean akhir yang tertunda sebelum menonaktifkan antrean lebih lanjut.

  • Untuk mematikan DispatcherQueue yang berjalan pada utas khusus dengan perulangan pesan milik DispatcherQueue, panggil metode DispatcherQueueController.ShutdownQueueAsync .
  • Untuk skenario di mana aplikasi memiliki perulangan pesan arbitrer (misalnya, Kepulauan XAML), panggil metode DispatcherQueueController.ShutdownQueue yang sinkron. Metode itu meningkatkan peristiwa matikan, dan menguras DispatcherQueue secara sinkron pada utas panggilan.

Saat Anda memanggil DispatcherQueueController.ShutdownQueueAsync atau DispatcherQueueController.ShutdownQueue, urutan peristiwa yang diangkat adalah sebagai berikut:

  • ShutdownStarting. Ditujukan untuk ditangani aplikasi.
  • FrameworkShutdownStarting. Ditujukan untuk kerangka kerja yang akan ditangani.
  • FrameworkShutdownCompleted. Ditujukan untuk kerangka kerja yang akan ditangani.
  • ShutdownCompleted. Ditujukan untuk ditangani aplikasi.

Peristiwa dipisahkan menjadi kategori aplikasi/kerangka kerja sehingga pematian tertib dapat dicapai. Artinya, dengan secara eksplisit meningkatkan pematian aplikasi menjelang peristiwa pematian kerangka kerja, tidak ada bahaya bahwa komponen kerangka kerja akan berada dalam keadaan tidak dapat digunakan saat aplikasi berliku.

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

Perulangan pesan terluar dan rekursif

DispatcherQueue mendukung perulangan pesan kustom. Namun, untuk aplikasi sederhana yang tidak memerlukan kustomisasi, kami menyediakan implementasi default. Itu menghapus beban dari pengembang, dan membantu memastikan perilaku yang benar secara konsisten.

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

Manajemen dispatcher sistem

Beberapa komponen SDK Aplikasi Windows (misalnya, MicaController) bergantung pada komponen sistem yang pada gilirannya memerlukan Sistem DispatcherQueue (Windows.System.DispatcherQueue) yang berjalan pada utas.

Dalam kasus tersebut, komponen yang memiliki dependensi DispatcherQueue sistem memanggil metode EnsureSystemDispatcherQueue, membebaskan aplikasi Anda dari mengelola sistem DispatcherQueue.

Dengan metode yang disebut, SDK Aplikasi Windows DispatcherQueue mengelola masa pakai sistem DispatcherQueue secara otomatis, mematikan sistem DispatcherQueue bersama SDK Aplikasi Windows DispatcherQueue. Komponen mungkin mengandalkan peristiwa pematian SDK Aplikasi Windows dan sistem DispatcherQueue untuk memastikan bahwa mereka melakukan pembersihan yang tepat setelah perulangan pesan keluar.

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

Integrasi AppWindow

Kelas AppWindow memiliki fungsionalitas yang mengintegrasikannya dengan DispatcherQueue, sehingga objek AppWindow dapat secara otomatis dihancurkan ketika metode DispatcherQueueController.ShutdownQueueAsync atau DispatcherQueueController.ShutdownQueue dipanggil.

Ada juga properti AppWindow yang memungkinkan penelepon untuk mengambil DispatcherQueue yang terkait dengan AppWindow; menyelaraskannya dengan objek lain di namespace Komposisi dan Input .

AppWindow memerlukan keikutsertaan eksplisit Anda untuk mengetahui 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()};

    var 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.Destoyed
    // event will be raised since the AppWindow instance is associated with the DispatcherQueue.
    dispatcherQueueController.ShutdownQueue();
}