Usando a API de hospedagem XAML do WinRT em um aplicativo da área de trabalho C++ (Win32)

Importante

Este tópico usa ou menciona tipos do repositório GitHub CommunityToolkit/Microsoft.Toolkit.Win32. Para saber mais sobre o suporte a ilhas XAML, confira o Aviso de ilhas XAML nesse repositório.

A partir do Windows 10, versão 1903, aplicativos da área de trabalho não UWP (incluindo os aplicativos C++ de desktop (Win32), WPF e Windows Forms) podem usar a API de hospedagem XAML do WinRT para hospedar controles XAML do WinRT em qualquer elemento da interface do usuário que esteja associado a um HWND (identificador de janela). Essa API permite que aplicativos da área de trabalho não UWP usem os recursos mais recentes da interface do usuário do Windows que só estão disponíveis por meio de controles XAML do WinRT. Por exemplo, aplicativos da área de trabalho não UWP podem usar essa API para hospedar controles XAML do WinRT que usam o Sistema Fluent Design e dão suporte ao Windows Ink.

A API de hospedagem XAML do WinRT fornece a base para um conjunto mais amplo de controles que estamos fornecendo para permitir que os desenvolvedores tragam a interface do usuário do Fluent para aplicativos da área de trabalho não UWP. Esse recurso é chamado de Ilhas XAML. Para obter uma visão geral desse recurso, confira Hospedar controles XAML do WinRT em aplicativos da área de trabalho (Ilhas XAML).

Observação

Caso tenha comentários sobre as Ilhas XAML, crie um problema no repositório Microsoft.Toolkit.Win32 e deixe seus comentários nele.

A API de hospedagem XAML do WinRT é a escolha certa para seu aplicativo da área de trabalho?

A API de hospedagem XAML do WinRT fornece a infraestrutura de baixo nível para hospedar controles XAML do WinRT em aplicativos da área de trabalho. Alguns tipos de aplicativos da área de trabalho têm a opção de usar APIs alternativas e mais convenientes para atingir esse objetivo.

  • Se você tiver um aplicativo da área de trabalho C++ e quiser hospedar os controles XAML do WinRT no seu aplicativo, precisará usar a API de hospedagem XAML do WinRT. Não há alternativas para esses tipos de aplicativos.

  • Para aplicativos WPF e Windows Forms, é altamente recomendável que você use os controles .NET da Ilha XAML no Windows Community Toolkit em vez de usar a API de hospedagem XAML do WinRT diretamente. Esses controles usam a API de hospedagem XAML do WinRT internamente e implementam todo o comportamento que você precisaria processar por conta própria se usasse a API de hospedagem XAML do WinRT diretamente, incluindo a navegação por teclado e as alterações de layout.

Como recomendamos que apenas os aplicativos da área de trabalho C++ usem a API de hospedagem XAML do WinRT, este artigo fornece principalmente instruções e exemplos para aplicativos da área de trabalho C++. No entanto, você poderá usar a API de hospedagem XAML do WinRT em aplicativos WPF e Windows Forms, se preferir. Este artigo aponta para o código-fonte relevante dos controles de host para WPF e Windows Forms no Windows Community Toolkit para que você possa ver como a API de hospedagem XAML do WinRT é usada por esses controles.

Como usar a API de hospedagem XAML

Para seguir instruções passo a passo com exemplos de código para usar a API de hospedagem XAML em aplicativos para desktop C++, confira estes artigos:

Exemplos

A maneira como você usa a API de hospedagem XAML do WinRT em seu código depende do tipo de aplicativo, do design do seu aplicativo e de outros fatores. Para ajudar a ilustrar como usar essa API no contexto de um aplicativo completo, este artigo refere-se ao código dos exemplos a seguir.

C++ de desktop (Win32)

Os seguintes exemplos demonstram como usar a API de hospedagem XAML do WinRT em um aplicativo da área de trabalho C++:

  • Exemplo de Ilha XAML. Este exemplo demonstra uma implementação básica de hospedagem de um controle XAML do WinRT em um aplicativo de desktop C++ não empacotado.

  • Ilha XAML com exemplo de controle personalizado. Este exemplo demonstra uma implementação completa de hospedagem de um controle XAML do WinRT personalizado em um aplicativo da área de trabalho C++ empacotado, bem como o processamento de outros comportamentos, como a entrada de teclado e a navegação de foco.

WPF e Windows Forms

O controle WindowsXamlHost no Windows Community Toolkit serve como um exemplo de referência para usar a API de hospedagem XAML do WinRT nos aplicativos Windows Forms e WPF. O código-fonte está disponível nos seguintes locais:

Observação

Recomendamos que você use os controles .NET da Ilha XAML no Windows Community Toolkit em vez de usar a API de hospedagem XAML do WinRT diretamente nos aplicativos Windows Forms e WPF. Os links de exemplo do Windows Forms e WPF neste artigo são apenas para fins ilustrativos.

Arquitetura da API

A API de hospedagem XAML do WinRT inclui os tipos principais de Windows Runtime e interfaces COM.

Tipo ou interface Descrição
WindowsXamlManager Essa classe representa a estrutura de XAML UWP. Essa classe fornece um único método estático InitializeForCurrentThread que inicializa a estrutura XAML UWP no thread atual no aplicativo da área de trabalho.
DesktopWindowXamlSource Essa classe representa uma instância do conteúdo do XAML UWP que você está hospedando em seu aplicativo da área de trabalho. O membro mais importante dessa classe é a propriedade de Content. Atribua essa propriedade a um Windows.UI.Xaml.UIElement que você queira hospedar. Essa classe também tem outros membros para rotear a navegação de foco de teclado para dentro e fora das Ilhas XAML.
IDesktopWindowXamlSourceNative Essa interface COM fornece o método AttachToWindow, que você usa para anexar uma Ilha XAML de seu aplicativo a um elemento pai da interface do usuário. Cada objeto DesktopWindowXamlSource implementa essa interface.
IDesktopWindowXamlSourceNative2 Essa interface COM fornece o método PreTranslateMessage, que permite à estrutura XAML UWP processar determinadas mensagens do Windows corretamente. Cada objeto DesktopWindowXamlSource implementa essa interface.

O diagrama a seguir ilustra a hierarquia de objetos em uma Ilha XAML hospedada em um aplicativo da área de trabalho.

  • No nível base está o elemento de interface do usuário em seu aplicativo em que você deseja hospedar a Ilha XAML. Esse elemento de interface do usuário deve ter um identificador de janela (HWND). Exemplos de elementos da interface do usuário nos quais você pode hospedar uma Ilha XAML incluem uma janela para aplicativos para desktop C++, um System.Windows.Interop.HwndHost para aplicativos WPF e um System.Windows.Forms.Control para aplicativos do Windows Forms.

  • No próximo nível está um objeto DesktopWindowXamlSource. Esse objeto fornece a infraestrutura para hospedar a Ilha XAML. Seu código é responsável por criar esse objeto e anexá-lo ao elemento pai da interface do usuário.

  • Quando você cria um DesktopWindowXamlSource, esse objeto cria automaticamente uma janela filho nativa para hospedar seu controle XAML do WinRT. Essa janela filho nativa é basicamente abstraída de seu código, mas você pode acessar o identificador (HWND), caso seja necessário.

  • Por fim, no nível superior está o controle XAML do WinRT que você deseja hospedar em seu aplicativo da área de trabalho. Pode ser qualquer objeto UWP derivado de Windows.UI.Xaml.UIElement, incluindo qualquer controle XAML do WinRT fornecido pelo SDK do Windows, bem como controles personalizados do usuário.

Arquitetura DesktopWindowXamlSource

Observação

Ao hospedar as Ilhas XAML em um aplicativo da área de trabalho, você pode ter várias árvores de conteúdo XAML em execução no mesmo thread simultaneamente. Para acessar o elemento raiz de uma árvore de conteúdo XAML em uma Ilha XAML e obter informações relacionadas sobre o contexto no qual ele está hospedado, use a classe XamlRoot. As APIs CoreWindow, ApplicationView e Window não fornecerão as informações corretas para as Ilhas XAML. Para obter mais informações, consulte esta seção.

Práticas recomendadas

Ao usar a API de hospedagem XAML do WinRT, siga estas práticas recomendadas para cada thread que hospeda os controles XAML do WinRT:

Solução de problemas

Erro ao usar a API de hospedagem XAML do WinRT em um aplicativo UWP

Problema Resolução
Seu aplicativo recebe uma COMException com a seguinte mensagem: "Não foi possível ativar DesktopWindowXamlSource. Este tipo não pode ser usado em um aplicativo UWP." ou "Não é possível ativar WindowsXamlManager. Esse tipo não pode ser usado em um aplicativo UWP." Esse erro indica que você está tentando usar a API de hospedagem XAML do WinRT (especificamente, está tentando criar uma instância dos tipos DesktopWindowXamlSource ou WindowsXamlManager) em um aplicativo UWP. A API de hospedagem XAML do WinRT destina-se apenas a ser usada em aplicativos não UWP da área de trabalho, como aplicativos da área de trabalho WPF, Windows Forms e C++.

Erro ao tentar usar os tipos WindowsXamlManager ou DesktopWindowXamlSource

Problema Resolução
Seu aplicativo recebe uma exceção com a seguinte mensagem: "WindowsXamlManager e DesktopWindowXamlSource têm suporte para aplicativos destinados à versão 10.0.18226.0 e posterior do Windows. Verifique o manifesto do aplicativo ou o manifesto do pacote e certifique-se de que a propriedade MaxTestedVersion esteja atualizada." Esse erro indica que seu aplicativo tentou usar os tipos WindowsXamlManager ou DesktopWindowXamlSource na API de hospedagem XAML do WinRT, mas o sistema operacional não pode determinar se o aplicativo foi criado para o Windows 10, versão 1903 ou posterior. A API de hospedagem XAML do WinRT foi introduzida pela primeira vez como versão prévia em uma versão anterior do Windows 10, mas só tem suporte a partir do Windows 10, versão 1903.

Para resolver esse problema, crie um pacote MSIX para o aplicativo e execute-o do pacote ou instale o pacote NuGet Microsoft.Toolkit.Win32.UI.SDK em seu projeto.

Erro ao anexar a uma janela em um thread diferente

Problema Resolução
Seu aplicativo recebe uma COMException com a seguinte mensagem: "O método AttachToWindow falhou porque o HWND especificado foi criado em um thread diferente". Esse erro indica que seu aplicativo chamou o método IDesktopWindowXamlSourceNative::AttachToWindow e passou o HWND de uma janela que foi criada em um thread diferente. Você deve passar esse método a HWND de uma janela que foi criada no mesmo thread que o código do qual você está chamando o método.

Erro ao anexar a uma janela em uma janela de nível superior diferente

Problema Resolução
Seu aplicativo recebe uma COMException com a seguinte mensagem: "O método AttachToWindow falhou porque o HWND especificado descende de uma janela de nível superior diferente do HWND que foi enviado anteriormente para AttachToWindow no mesmo thread". Esse erro indica que seu aplicativo chamou o método IDesktopWindowXamlSourceNative:: AttachToWindow e passou o HWND de uma janela que descende de uma janela de nível superior diferente daquela que você especificou em uma chamada anterior para esse método no mesmo thread.

Depois que o aplicativo chama AttachToWindow em um thread específico, todos os outros objetos DesktopWindowXamlSource no mesmo thread só podem ser anexados a janelas descendentes da mesma janela de nível superior passada na primeira chamada para AttachToWindow. Quando todos os objetos DesktopWindowXamlSource estão fechados para um thread específico, o próximo DesktopWindowXamlSource é liberado para anexar a qualquer janela novamente.

Para resolver esse problema, feche todos os objetos DesktopWindowXamlSource associados a outras janelas de nível superior nesse thread ou crie um novo thread para esse DesktopWindowXamlSource.