Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
Aspectos destacados
- La clase DispatcherQueue de la SDK de Aplicaciones para Windows administra una cola prioritaria en la que las tareas de un subproceso se ejecutan de forma serie.
- Proporciona un medio para que los subprocesos en segundo plano ejecuten código en un subproceso de DispatcherQueue (por ejemplo, el subproceso de la interfaz de usuario en el que los objetos con afinidad de subproceso están activos).
- La clase se integra correctamente con cualquier bucle de mensajes. Por ejemplo, admite el patrón habitual de Win32 de bucles de mensajes anidados.
- La clase AppWindow se integra con DispatcherQueue, cuando se apaga un dispatcherQueue para un subproceso determinado, las instancias de AppWindow se destruyen automáticamente.
- Proporciona un medio para registrar un delegado al que se llama cuando expira un tiempo de espera.
- Proporciona eventos que permiten a los componentes saber cuándo sale un bucle de mensajes y, opcionalmente, aplazar ese apagado hasta que se complete el trabajo pendiente. Eso garantiza que los componentes que usan la DispatcherQueue, pero no controlan el bucle de mensajes, puedan llevar a cabo tareas de limpieza en el propio subproceso cuando el bucle finaliza.
- DispatcherQueue es un singleton de subproceso (puede haber como máximo uno de ellos en ejecución en cualquier subproceso determinado). De forma predeterminada, un subproceso no tiene DispatcherQueue.
- Un propietario del subproceso puede crear un DispatcherQueueController para inicializar dispatcherQueue para el subproceso. En ese momento, cualquier código puede tener acceso a DispatcherQueue del subproceso; pero solo el propietario de DispatcherQueueController tiene acceso al método DispatcherQueueController.ShutdownQueue , que purga dispatcherQueue y genera eventos ShutdownStarting y ShutdownCompleted .
- El propietario del bucle de mensajes más externo debe crear una instancia de DispatcherQueue. Solo el código encargado de ejecutar el bucle de mensajes más externo de un subproceso sabe cuándo se ha completado el envío, que es el momento adecuado para apagar DispatcherQueue. Esto significa que los componentes que dependen de DispatcherQueue no deben crear dispatcherQueue a menos que posean el bucle de mensajes del subproceso.
Resumen
Después de que un subproceso salga de su bucle de eventos, debe apagar su DispatcherQueue. Al hacerlo, se generan los eventos ShutdownStarting y ShutdownCompleted y se purgan los elementos en cola pendientes finales antes de deshabilitar la puesta en cola.
- Para apagar un dispatcherQueue que se ejecuta en un subproceso dedicado con un bucle de mensajes de propiedad de DispatcherQueue, llame al método DispatcherQueueController.ShutdownQueueAsync .
- En escenarios en los que la aplicación posee un bucle de mensajes arbitrario (por ejemplo, islas XAML), llame al método DispatcherQueueController.ShutdownQueue sincrónico. Ese método genera eventos de cierre y vacía la DispatcherQueue de forma sincrónica en el subproceso de llamada.
Al llamar a DispatcherQueueController.ShutdownQueueAsync o DispatcherQueueController.ShutdownQueue, el orden de los eventos generados es el siguiente:
- ShutdownStarting. Diseñado para que las aplicaciones lo gestionen.
- FrameworkShutdownStarting. Pensado para que los frameworks lo gestionen.
- FrameworkShutdownCompleted. Pensado para que los frameworks lo gestionen.
- ShutdownCompleted. Pensado para que lo gestionen las aplicaciones.
Los eventos se separan en categorías de aplicación o marco para que se pueda lograr el apagado ordenado. Es decir, al generar explícitamente el apagado de la aplicación antes de los eventos de cierre del marco, no hay ningún peligro de que un componente de marco esté en un estado inutilizable a medida que la aplicación deja de funcionar.
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();
}
Bucles de mensajes más externos y recursivos
DispatcherQueue admite bucles de mensajes personalizados. Sin embargo, para aplicaciones sencillas que no necesitan personalización, proporcionamos implementaciones predeterminadas. Esto elimina una carga de los desarrolladores y ayuda a garantizar un comportamiento coherentemente correcto.
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();
}
Administración del despachador del sistema
Algunos componentes de SDK de Aplicaciones para Windows (por ejemplo, MicaController) dependen de los componentes del sistema que, a su vez, requieren un sistema DispatcherQueue (Windows. System.DispatcherQueue) que se ejecuta en el subproceso.
En esos casos, el componente que tiene una dependencia dispatcherQueue del sistema llama al método EnsureSystemDispatcherQueue , lo que libera la aplicación de administrar un sistema DispatcherQueue.
Una vez llamado ese método, DispatcherQueue de SDK de Aplicaciones para Windows administra automáticamente el ciclo de vida de DispatcherQueue del sistema y apaga DispatcherQueue del sistema junto con DispatcherQueue de SDK de Aplicaciones para Windows. Los componentes pueden depender tanto de los eventos de apagado de SDK de Aplicaciones para Windows como de los de apagado del sistema DispatcherQueue para asegurarse de que llevan a cabo la limpieza adecuada después de que finalice el bucle de mensajes.
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();
}
Integración de AppWindow
La clase AppWindow tiene funcionalidad que la integra con dispatcherQueue, de modo que los objetos AppWindow se puedan destruir automáticamente cuando se llama al método DispatcherQueueController.ShutdownQueueAsync o DispatcherQueueController.ShutdownQueue .
También hay una propiedad de AppWindow que permite a los autores de llamadas recuperar el DispatcherQueue asociado a AppWindow; alinearlo con otros objetos en los espacios de nombres Composition y Input .
AppWindow necesita su consentimiento explícito para reconocer 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.Destoyed
// event will be raised since the AppWindow instance is associated with the DispatcherQueue.
dispatcherQueueController.ShutdownQueue();
}