Escenarios avanzados para islas XAML en aplicaciones de C++ de escritorio (Win32)

Importante

En este tema se usan o mencionan tipos del repositorio de GitHub CommunityToolkit/Microsoft.Toolkit.Win32. Para obtener información importante sobre la compatibilidad con islas XAML, consulte el Aviso de islas XAML en ese repositorio.

Los artículos sobre cómo hospedar un control estándar de UWP y hospedar un control UWP personalizado incluyen instrucciones y ejemplos para hospedar islas XAML en una aplicación de C++ de escritorio (Win32). Sin embargo, los ejemplos de código de estos artículos no controlan muchos escenarios avanzados que las aplicaciones de escritorio podrían necesitar para proporcionar una experiencia de usuario fluida. En este artículo se incluyen instrucciones para algunos de estos escenarios y se proporcionan vínculos a ejemplos de código relacionados.

Entrada de teclado

Para controlar correctamente la entrada del teclado para cada isla XAML, la aplicación debe pasar todos los mensajes de Windows al marco XAML de UWP para que ciertos mensajes se puedan procesar correctamente. Para ello, en algún lugar de la aplicación que pueda acceder al bucle de mensajes, convierte el objeto DesktopWindowXamlSource de cada isla XAML en una interfaz COM IDesktopWindowXamlSourceNative2. A continuación, llama al método PreTranslateMessage de esta interfaz y pasa el mensaje actual.

  • C++ de escritorio (Win32): la aplicación puede llamar a PreTranslateMessage directamente en el bucle de mensajes principal. Para ver un ejemplo, consulta el archivo XamlBridge.cpp.

  • WPF: La aplicación puede llamar a PreTranslateMessage desde el controlador de eventos del evento ComponentDispatcher.ThreadFilterMessage. Para ver un ejemplo, consulta el archivo WindowsXamlHostBase.Focus.cs en el kit de herramientas de la comunidad de Windows.

  • Windows Forms: La aplicación puede llamar a PreTranslateMessage desde una invalidación para el método Control.PreprocessMessage. Para ver un ejemplo, consulta el archivo WindowsXamlHostBase.KeyboardFocus.cs en el kit de herramientas de la comunidad de Windows.

Navegación del foco con el teclado

Cuando el usuario navega por los elementos de la interfaz de usuario de la aplicación mediante el teclado (por ejemplo, al presionar la tecla TAB o las teclas de dirección), deberás mover el foco dentro y fuera del objeto DesktopWindowXamlSource mediante programación. Cuando la navegación del usuario mediante el teclado alcance al objeto DesktopWindowXamlSource, mueve el foco al primer objeto Windows.UI.Xaml.UIElement en el orden de navegación de la interfaz de usuario. Continúa moviendo el foco a los siguientes objetos Windows.UI.Xaml.UIElement a medida que el usuario recorra los elementos y, a continuación, quita el foco de DesktopWindowXamlSource y regresa al elemento de interfaz de usuario principal.

La API de hospedaje XAML de UWP proporciona varios tipos y miembros para ayudarte a llevar a cabo estas tareas.

  • Cuando la navegación del teclado entra en DesktopWindowXamlSource, se genera el evento GotFocus. Controla este evento y mueve mediante programación el foco al primer objeto Windows.UI.Xaml.UIElement mediante el método NavigateFocus.

  • Cuando el usuario está en el último elemento activable de DesktopWindowXamlSource y presiona la tecla TAB o una tecla de dirección, se genera el evento TakeFocusRequested. Controla este evento y mueve mediante programación el foco al siguiente elemento activable de la aplicación host. Por ejemplo, en una aplicación WPF en la que el objeto DesktopWindowXamlSource está hospedado en una clase System.Windows.Interop.HwndHost, puedes usar el método MoveFocus para transferir el foco al siguiente elemento activable de la aplicación host.

Para ver ejemplos que muestran cómo realizar estas acciones en el contexto de una aplicación de ejemplo funcional, consulta los siguientes archivos de código:

Control de cambios de diseño

Cuando el usuario cambia el tamaño del elemento de la interfaz de usuario principal, debes controlar los cambios de diseño necesarios para asegurarte de que los controles de UWP se muestran según lo previsto. Estos son algunos escenarios importantes que se deben tener en cuenta.

  • En una aplicación de C++ de escritorio, cuando la aplicación controla el mensaje de WM_SIZE, se puede cambiar la posición de la isla XAML hospedada mediante la función SetWindowPos. Para ver un ejemplo, consulta el archivo de código SampleApp.cpp.

  • Cuando el elemento principal de la interfaz de usuario necesita obtener el tamaño del área rectangular necesaria para ajustarse al objeto Windows.UI.Xaml.UIElement que hospedas en DesktopWindowXamlSource, llama al método Measure de Windows.UI.Xaml.UIElement. Por ejemplo:

    • En una aplicación de WPF, puedes hacerlo desde el método MeasureOverride de la clase HwndHost que hospeda a DesktopWindowXamlSource. Para ver un ejemplo, consulta el archivo WindowsXamlHostBase.Layout.cs en el kit de herramientas de la comunidad de Windows.

    • En una aplicación de Windows Forms, puedes hacerlo desde el método GetPreferredSize de la clase Control que hospeda a DesktopWindowXamlSource. Para ver un ejemplo, consulta el archivo WindowsXamlHostBase.Layout.cs en el kit de herramientas de la comunidad de Windows.

  • Cuando se cambie el tamaño del elemento principal de la interfaz de usuario, llama al método Arrange del objeto raíz Windows.UI.Xaml.UIElement que se hospeda en DesktopWindowXamlSource. Por ejemplo:

    • En una aplicación de WPF, puedes hacerlo desde el método ArrangeOverride del objeto HwndHost que hospeda a DesktopWindowXamlSource. Para ver un ejemplo, consulta el archivo WindowsXamlHost.Layout.cs en el kit de herramientas de la comunidad de Windows.

    • En una aplicación de Windows Forms, puedes hacerlo desde el controlador del evento SizeChanged de la clase Control que hospeda a DesktopWindowXamlSource. Para ver un ejemplo, consulta el archivo WindowsXamlHost.Layout.cs en el kit de herramientas de la comunidad de Windows.

Administración de los cambios de PPP

El marco XAML de UWP administra automáticamente los cambios de PPP para los controles de UWP hospedados (por ejemplo, cuando el usuario arrastra una ventana entre monitores con distintos PPP de pantalla). Para disfrutar de la mejor experiencia, se recomienda que la aplicación de Windows Forms, WPF o de C++ de escritorio esté configurada para incluir reconocimiento de PPP por monitor.

Para realizar esta configuración en la aplicación, agrega un manifiesto del ensamblado en paralelo al proyecto y establece el elemento <dpiAwareness> en PerMonitorV2. Para obtener más información acerca de este valor, consulta la descripción de DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
    <application xmlns="urn:schemas-microsoft-com:asm.v3">
        <windowsSettings>
            <dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
        </windowsSettings>
    </application>
</assembly>