Uso de la API de hospedaje XAML de WinRT en una aplicación 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.

A partir de Windows 10, versión 1903, las aplicaciones de escritorio que no son de UWP (incluidas las aplicaciones de C++ de escritorio [Win32], WPF y Windows Forms) pueden usar la API de hospedaje XAML de WinRT para hospedar controles XAML de WinRT en cualquier elemento de la interfaz de usuario que esté asociado con un identificador de ventana (HWND). Esta API permite que las aplicaciones de escritorio que no son de UWP usen las últimas características de la interfaz de usuario de Windows que solo están disponibles mediante los controles XAML de WinRT. Por ejemplo, las aplicaciones de escritorio que no son de UWP pueden usar esta API para hospedar controles XAML de WinRT que usan el Sistema Fluent Design y admiten Windows Ink.

La API de hospedaje XAML de WinRT proporciona la base para un conjunto más amplio de controles que se proporciona para permitir que los desarrolladores incorporen la interfaz de usuario de Fluent a aplicaciones de escritorio que no son de UWP. Esta característica se conoce como islas XAML. Para obtener información general sobre esta característica, consulta Cómo usar los controles XAML de WinRT en aplicaciones de escritorio (islas XAML).

Nota

Si tienes comentarios sobre las islas XAML, crea un nuevo problema en el repositorio de Microsoft.Toolkit.Win32 y deja los comentarios allí.

¿La API de hospedaje XAML de WinRT es la opción adecuada para su aplicación de escritorio?

La API de hospedaje XAML de WinRT proporciona la infraestructura de bajo nivel para hospedar controles XAML de WinRT en aplicaciones de escritorio. Algunos tipos de aplicaciones de escritorio tienen la opción de usar API alternativas más adecuadas para lograr este objetivo.

  • Si tiene una aplicación de escritorio de C++ nativa y quiere hospedar los controles XAML de WinRT en la aplicación, debe usar la API de hospedaje XAML de WinRT. No hay alternativas para estos tipos de aplicaciones.

  • En el caso de las aplicaciones de WPF y Windows Forms, se recomienda encarecidamente usar los controles .NET de las islas XAML en el kit de herramientas de la comunidad de Windows en lugar de usar directamente la API de hospedaje XAML de WinRT. Estos controles usan la API de hospedaje XAML de WinRT internamente e implementan todo el comportamiento que, de lo contrario, tendría que controlar usted mismo si usara la API de hospedaje XAML de WinRT directamente, incluida la navegación con el teclado y los cambios de diseño.

Dado que se recomienda que solo las aplicaciones de C++ de escritorio usen la API de hospedaje XAML de WinRT, en este artículo principalmente se proporcionan instrucciones y ejemplos para aplicaciones de C++ de escritorio. Sin embargo, puede usar la API de hospedaje XAML de WinRT en aplicaciones de WPF y Windows Forms si lo desea. En este artículo se hace referencia al código fuente pertinente para los controles host para WPF y Windows Forms en el kit de herramientas de la comunidad de Windows, de modo que pueda ver cómo dichos controles usan la API de hospedaje XAML de WinRT.

Información sobre cómo usar la API de hospedaje XAML

Para seguir las instrucciones detalladas con ejemplos de código para usar la API de hospedaje XAML en aplicaciones de C++ de escritorio, consulte estos artículos:

Ejemplos

La forma de usar la API de hospedaje XAML de WinRT en el código depende del tipo de aplicación, el diseño de la aplicación y otros factores. Para ayudar a ilustrar el uso de esta API en el contexto de una aplicación completa, en este artículo se hace referencia al código de los ejemplos siguientes.

C++ de escritorio (Win32)

Los ejemplos siguientes demuestran cómo usar la API de hospedaje XAML de WinRT en una aplicación de C++ de escritorio:

  • Ejemplo sencillo de islas XAML. Este ejemplo demuestra una implementación básica para alojar un control WinRT XAML en una aplicación de escritorio C++ sin empaquetar.

  • Ejemplo de islas XAML con controles personalizados. En este ejemplo se muestra una implementación completa del hospedaje de un control XAML personalizado de WinRT en una aplicación de C++ de escritorio empaquetada, así como el control de otro comportamiento, como la entrada de teclado y la navegación del foco.

WPF y Windows Forms

El control WindowsXamlHost del kit de herramientas de la comunidad de Windows sirve como ejemplo de referencia para usar la API de hospedaje XAML de WinRT en aplicaciones de WPF y Windows Forms. El código fuente se encuentra disponible en las siguientes ubicaciones:

Nota

Se recomienda encarecidamente usar los controles .NET de las islas XAML en el kit de herramientas de la comunidad de Windows en lugar de usar directamente la API de hospedaje XAML de WinRT en aplicaciones de WPF y Windows Forms. Los vínculos e ejemplo de WPF y Windows Forms de este artículo se ofrecen solo para fines ilustrativos.

Arquitectura de la API

La API de hospedaje XAML de WinRT incluye estos tipos principales de Windows Runtime e interfaces COM.

Tipo o interfaz Descripción
WindowsXamlManager Esta clase representa el marco XAML de UWP. Esta clase proporciona un solo método estático InitializeForCurrentThread que inicializa el marco XAML de UWP en el subproceso actual en la aplicación de escritorio.
DesktopWindowXamlSource Esta clase representa una instancia de contenido XAML de UWP que se hospeda en la aplicación de escritorio. El miembro más importante de esta clase es la propiedad Content. Esta propiedad se asigna a un elemento Windows.UI.Xaml.UIElement que se desea hospedar. Esta clase también tiene otros miembros para la navegación del foco de teclado de enrutamiento dentro y fuera de las islas XAML.
IDesktopWindowXamlSourceNative Esta interfaz COM proporciona el método AttachToWindow, que se usa para adjuntar una isla XAML en la aplicación a un elemento primario de la interfaz de usuario. Cada objeto DesktopWindowXamlSource implementa esta interfaz.
IDesktopWindowXamlSourceNative2 Esta interfaz COM proporciona el método PreTranslateMessage, que permite al marco XAML de UWP procesar correctamente determinados mensajes de Windows. Cada objeto DesktopWindowXamlSource implementa esta interfaz.

En el diagrama siguiente se muestra la jerarquía de objetos de una isla XAML que se hospeda en una aplicación de escritorio.

  • En el nivel base, es el elemento de la interfaz de usuario de la aplicación donde deseas hospedar la isla XAML. Este elemento de la interfaz de usuario debe tener un identificador de ventana (HWND). Entre los ejemplos de elementos de interfaz de usuario en los que puede hospedar una isla XAML, se incluyen una ventana para las aplicaciones de C++ de escritorio, un elemento System.Windows.Interop.HwndHost para las aplicaciones de WPF y un elemento System.Windows.Forms.Control para las aplicaciones de Windows Forms.

  • En el siguiente nivel, se encuentra un objeto DesktopWindowXamlSource. Este objeto proporciona la infraestructura para hospedar la isla XAML. El código es responsable de crear este objeto y adjuntarlo al elemento primario de la interfaz de usuario.

  • Al crear un elemento DesktopWindowXamlSource, este objeto crea automáticamente una ventana secundaria nativa para hospedar el control XAML de WinRT. Esta ventana secundaria nativa se abstrae en su mayoría del código, pero puedes acceder a su identificador (HWND) si es necesario.

  • Por último, en el nivel superior se encuentra el control XAML de WinRT que quiere hospedar en la aplicación de escritorio. Puede ser cualquier objeto de UWP que se derive de Windows.UI.Xaml.UIElement, incluido cualquier control XAML de WinRT proporcionado por Windows SDK, así como controles de usuario personalizados.

DesktopWindowXamlSource architecture

Nota:

Al hospedar islas XAML en una aplicación de escritorio, puedes tener varios árboles de contenido XAML que se ejecuten en el mismo subproceso a la vez. Para acceder al elemento raíz de un árbol de contenido XAML en una isla XAML y obtener la información relacionada sobre el contexto en el que se hospeda, usa la clase XamlRoot. Las API CoreWindow, ApplicationView y Window no proporcionan la información correcta para las islas XAML. Para más información, consulte esta sección.

Procedimientos recomendados

Al usar la API de hospedaje XAML de WinRT, siga estos procedimientos recomendados para cada subproceso que hospeda controles XAML de WinRT:

Solucionar problemas

Error al usar la API de hospedaje XAML de WinRT en una aplicación para UWP

Problema Solución
La aplicación recibe una COMException con el siguiente mensaje: "No se puede activar DesktopWindowXamlSource. Este tipo no se puede usar en una aplicación para UWP o no se puede activar en WindowsXamlManager. Este tipo no se puede usar en una aplicación para UWP". Este error indica que está intentando usar la API de hospedaje XAML de WinRT (en concreto, está intentando crear una instancia de los tipos DesktopWindowXamlSource o WindowsXamlManager) en una aplicación para UWP. La API de hospedaje XAML de WinRT solo está pensada para usarse en aplicaciones de escritorio que no son de UWP, como aplicaciones de WPF, de Windows Forms y de C++ de escritorio.

Error al intentar usar los tipos WindowsXamlManager o DesktopWindowXamlSource

Problema Solución
La aplicación recibe una excepción con el siguiente mensaje: "WindowsXamlManager y DesktopWindowXamlSource se admiten para aplicaciones destinadas a Windows 10.0.18226.0 y posteriores. Comprueba el manifiesto de aplicación o el manifiesto de paquete y asegúrate de que la propiedad MaxTestedVersion esté actualizada". Este error indica que la aplicación intentó usar los tipos WindowsXamlManager o DesktopWindowXamlSource de la API de hospedaje XAML de WinRT, pero el sistema operativo no puede determinar si la aplicación se ha creado para tener como destino Windows 10, versión 1903, o posterior. La API de hospedaje XAML de WinRT se presentó por primera vez como una versión preliminar en una versión anterior de Windows 10, pero solo se admite a partir de Windows 10, versión 1903.

Para resolver este problema, crea un paquete MSIX para la aplicación y ejecútala desde el paquete, o bien instala el paquete NuGet Microsoft.Toolkit.Win32.UI.SDK en el proyecto.

Error al adjuntar a una ventana en un subproceso diferente

Problema Solución
La aplicación recibe una COMException con el siguiente mensaje: "Error en el método AttachToWindow porque el HWND especificado se creó en un subproceso diferente". Este error indica que la aplicación llamó al método IDesktopWindowXamlSourceNative::AttachToWindow y le pasó el HWND de una ventana creada en un subproceso diferente. Debes pasar a este método el HWND de una ventana creada en el mismo subproceso que el código desde el que llamas al método.

Error al adjuntar a una ventana en una ventana de primer nivel distinta

Problema Solución
La aplicación recibe un valor COMException con el siguiente mensaje: "Error en el método AttachToWindow porque el HWND especificado desciende de una ventana de primer nivel distinta de la del HWND que se pasó previamente a AttachToWindow en el mismo subproceso". Este error indica que la aplicación llamó al método IDesktopWindowXamlSourceNative::AttachToWindow y le pasó el HWND de una ventana que desciende de una ventana de primer nivel distinta de la ventana especificada en una llamada anterior a este método en el mismo subproceso.

Una vez que la aplicación llama a AttachToWindow en un subproceso determinado, todos los demás objetos DesktopWindowXamlSource del mismo subproceso solo pueden asociarse a ventanas que son descendientes de la misma ventana de primer nivel que se pasó en la primera llamada a AttachToWindow. Cuando se cierran todos los objetos DesktopWindowXamlSource para un subproceso determinado, el siguiente elemento DesktopWindowXamlSource es gratis para volver a asociarlo a cualquier ventana.

Para resolver este problema, cierra todos los objetos DesktopWindowXamlSource que estén enlazados a otras ventanas de primer nivel en este subproceso, o crea un subproceso para este elemento DesktopWindowXamlSource.