Compartilhar via


Hospedar um controle WinRT XAML personalizado em um aplicativo WPF usando as Ilhas XAML

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.

Este artigo demonstra como usar o controle WindowsXamlHost no Windows Community Toolkit para hospedar um controle WinRT XAML personalizado em um aplicativo WPF direcionado ao .NET Core 3.1. O controle personalizado contém vários controles internos da SDK do Windows e associa uma propriedade em um dos controles WinRT XAML a uma cadeia de caracteres no aplicativo WPF. Este artigo também demonstra como hospedar um controle da biblioteca WinUI.

Embora este artigo demonstre como fazer isso em um aplicativo WPF, o processo é semelhante para um aplicativo do Windows Forms. Para uma visão geral sobre a hospedagem de controles WinRT XAML em aplicativos WPF e do Windows Forms, confira este artigo.

Observação

Usar Ilhas XAML para hospedar controles WinRT XAML no WPF, bem como em aplicativos do Windows Forms, atualmente é compatível somente com aplicativos destinados ao .NET Core 3.x. As Ilhas XAML ainda não têm suporte em aplicativos destinados ao .NET nem em aplicativos de qualquer versão do .NET Framework.

Componentes necessários

Para hospedar um controle WinRT XAML personalizado em um aplicativo WPF (ou do Windows Forms), você precisará dos componentes a seguir em sua solução. Este artigo fornece instruções para criar cada um desses componentes.

  • O projeto e o código-fonte para seu aplicativo. O uso do controle WindowsXamlHost para hospedar controles personalizados só é compatível com aplicativos direcionados ao .NET Core 3.x.

  • O controle WinRT XAML personalizado. Você precisará do código-fonte do controle personalizado que deseja hospedar para compilá-lo com seu aplicativo. Normalmente, o controle personalizado é definido em um projeto de biblioteca de classes UWP que você faz referência na mesma solução que o seu projeto do WPF ou Windows Forms.

  • Um projeto de aplicativo UWP que define uma Classe de aplicativo raiz que deriva de XamlApplication. Seu projeto do WPF ou do Windows Forms deve ter acesso a uma instância da classe Microsoft.Toolkit.Win32.UI.XamlHost.XamlApplication fornecida pelo Windows Community Toolkit para que ele possa descobrir e carregar controles XAML personalizados da UWP. A maneira recomendada para fazer isso é definir esse objeto em um projeto de aplicativo UWP separado que faça parte da solução do seu aplicativo WPF ou Windows Forms.

    Observação

    Sua solução pode conter apenas um projeto que define um objeto XamlApplication. Todos os controles WinRT XAML personalizados no aplicativo compartilham o objeto XamlApplication. O projeto que define o objeto XamlApplication precisa incluir referências a todas as outras bibliotecas WinRT e projetos usados para hospedar controles na Ilha XAML.

Criar um projeto do WPF

Antes de começar, siga estas instruções para criar um projeto do WPF e configurá-lo para hospedar Ilhas XAML. Se você já tiver um projeto do WPF, poderá adaptar essas etapas e exemplos de código para seu projeto.

Observação

Se você já tiver um projeto que se destina ao .NET Framework, precisará migrá-lo para o .NET Core 3.1. Para obter mais informações, confira esta série do blog.

  1. Caso ainda não tenha feito, instale a versão mais recente do SDK do .NET Core 3.1.

  2. No Visual Studio 2019, crie um projeto Aplicativo WPF (.NET Core) .

  3. Verifique se as referências de pacote estão habilitadas:

    1. No Visual Studio, clique em Tools -> Gerenciador de Pacotes NuGet -> Configurações do Gerenciador de Pacotes.
    2. Verifique se PackageReference está selecionado para Formato de gerenciamento de pacotes padrão.
  4. Clique com o botão direito do mouse no seu projeto do WPF no Gerenciador de Soluções e escolha Gerenciar Pacotes NuGet.

  5. Selecione a guia Procurar, pesquise o pacote Microsoft.Toolkit.Wpf.UI.XamlHost e instale a versão estável mais recente. Esse pacote fornece tudo o que você precisa para usar o controle WindowsXamlHost para hospedar um controle WinRT XAML, incluindo outros pacotes NuGet relacionados.

    Observação

    Os aplicativos do Windows Forms precisam usar o pacote Microsoft.Toolkit.Forms.UI.XamlHost.

  6. Configure sua solução para destino a uma plataforma específica, como x86 ou x64. Os controles WinRT XAML personalizados não são compatíveis com projetos direcionados a Qualquer CPU.

    1. No Gerenciador de Soluções, clique com o botão direito do mouse no nó da solução e selecione Propriedades>Propriedades de Configuração>Gerenciador de Configurações.
    2. Em Plataforma da solução ativa, selecione Nova.
    3. Na caixa de diálogo Nova Plataforma de Solução, selecione x64 ou x86 e pressione OK.
    4. Feche as caixas de diálogo abertas.

Definir uma classe XamlApplication em um projeto de aplicativo UWP

Agora, adicione um projeto de aplicativo UWP à sua solução e revise a classe App padrão neste projeto para derivar da classe Microsoft.Toolkit.Win32.UI.XamlHost.XamlApplication fornecida pelo Windows Community Toolkit. Essa classe dá suporte à interface IXamlMetadataProvider, que permite que o aplicativo descubra e carregue metadados para controles XAML personalizados da UWP em assemblies no diretório atual do seu aplicativo no tempo de execução. Essa classe também inicializa a estrutura XAML da UWP para o thread atual.

  1. No Gerenciador de Soluções, clique com o botão direito do mouse no nó da solução e selecione Adicionar>Novo Projeto.

  2. Adicione um projeto Aplicativo em Branco (Universal do Windows) à sua solução. Verifique se a versão de destino e a versão mínima estão definidas como Windows 10, versão 1903 (build 18362) ou uma versão posterior.

  3. No projeto de aplicativo UWP, instale o pacote NuGet Microsoft.Toolkit.Win32.UI.XamlApplication (versão estável mais recente).

  4. Abra o arquivo App.xaml e substitua o conteúdo desse arquivo pelo XAML a seguir. Substitua MyUWPApp pelo namespace do seu projeto de aplicativo UWP.

    <xaml:XamlApplication
        x:Class="MyUWPApp.App"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:xaml="using:Microsoft.Toolkit.Win32.UI.XamlHost"
        xmlns:local="using:MyUWPApp">
    </xaml:XamlApplication>
    
  5. Abra o arquivo App.xaml.cs e substitua o conteúdo desse arquivo pelo código a seguir. Substitua MyUWPApp pelo namespace do seu projeto de aplicativo UWP.

    namespace MyUWPApp
    {
        public sealed partial class App : Microsoft.Toolkit.Win32.UI.XamlHost.XamlApplication
        {
            public App()
            {
                this.Initialize();
            }
        }
    }
    
  6. Exclua o arquivo MainPage.xaml do projeto de aplicativo UWP.

  7. Limpe o projeto de aplicativo UWP e compile-o.

Adicionar uma referência ao projeto UWP em seu projeto WPF

  1. Especifique a versão de estrutura compatível no arquivo de projeto do WPF.

    1. No Gerenciador de Soluções, clique duas vezes no nó do projeto WPF para abrir o arquivo de projeto no editor.

    2. No primeiro elemento PropertyGroup, adicione o elemento filho a seguir. Altere a parte 19041 do valor conforme necessário para fazer a correspondência com o build de SO de destino e mínimo do projeto UWP.

      <AssetTargetFallback>uap10.0.19041</AssetTargetFallback>
      

      Quando você terminar, o elemento PropertyGroup deverá ser semelhante a este.

      <PropertyGroup>
          <OutputType>WinExe</OutputType>
          <TargetFramework>netcoreapp3.1</TargetFramework>
          <UseWPF>true</UseWPF>
          <Platforms>AnyCPU;x64</Platforms>
          <AssetTargetFallback>uap10.0.19041</AssetTargetFallback>
      </PropertyGroup>
      
  2. No Gerenciador de Soluções, clique com o botão direito do mouse no nó Dependências no projeto WPF e adicione uma referência ao seu projeto de aplicativo UWP.

Criar uma instância do objeto XamlApplication no ponto de entrada do aplicativo WPF

Em seguida, adicione o código ao ponto de entrada do aplicativo WPF para criar uma instância da classe App que você acabou de definir no projeto UWP (essa é a classe que agora é derivada de XamlApplication).

  1. No projeto do WPF, clique com o botão direito do mouse no nó do projeto, selecione Adicionar>Novo item e, em seguida, selecione Classe. Nomeie a classe como Programa e clique em Adicionar.

  2. Substitua a classe Program gerada pelo código a seguir e salve o arquivo. Substitua MyUWPApp pelo namespace do seu projeto de aplicativo UWP e substitua MyWPFApp pelo namespace do seu projeto de aplicativo WPF.

    public class Program
    {
        [System.STAThreadAttribute()]
        public static void Main()
        {
            using (new MyUWPApp.App())
            {
                MyWPFApp.App app = new MyWPFApp.App();
                app.InitializeComponent();
                app.Run();
            }
        }
    }
    
  3. Clique com o botão direito do mouse no nó do projeto e escolha Propriedades.

  4. Na guia Aplicativo das propriedades, clique na lista suspensa Objeto de inicialização e escolha o nome totalmente qualificado da classe Program que você adicionou na etapa anterior.

    Observação

    Por padrão, os projetos do WPF definem uma função de ponto de entrada Main em um arquivo de código gerado que não deve ser modificado. Essa etapa altera o ponto de entrada do seu projeto para o método Main da nova classe Program, o que permite que você adicione o código que é executado o quanto antes no processo de inicialização do aplicativo.

  5. Salve as alterações que você fez nas propriedades do projeto.

Criar um controle WinRT XAML personalizado

Para hospedar um controle WinRT XAML personalizado em seu aplicativo WPF, você precisa ter o código-fonte do controle para que possa compilá-lo com o aplicativo. Normalmente, os controles personalizados são definidos em um projeto de biblioteca de classes UWP para uma portabilidade mais fácil.

Nesta seção, você definirá um controle personalizado simples em um novo projeto de biblioteca de classes. Como alternativa, você pode definir o controle personalizado no projeto de aplicativo UWP criado na seção anterior. No entanto, essas etapas fazem isso em outro projeto de biblioteca de classes para fins ilustrativos, pois normalmente é assim que os controles personalizados são implementados para portabilidade.

Se você já tem um controle personalizado, pode usá-lo em vez do controle mostrado aqui. No entanto, ainda precisará configurar o projeto que contém o controle, conforme mostrado nestas etapas.

  1. No Gerenciador de Soluções, clique com o botão direito do mouse no nó da solução e selecione Adicionar>Novo Projeto.

  2. Adicione um projeto Biblioteca de Classes (Universal do Windows) à sua solução. Verifique se a versão de destino e a versão mínima estão definidas como o mesmo build de SO de destino e mínimo que o projeto UWP.

  3. Clique com o botão direito do mouse no arquivo de projeto e selecione Descarregar Projeto. Clique com o botão direito do mouse no arquivo de projeto novamente e selecione Editar.

  4. Antes do elemento de fechamento </Project>, adicione o XML a seguir para desabilitar algumas propriedades e, em seguida, salve o arquivo de projeto. Essas propriedades devem ser habilitadas para hospedar o controle personalizado em um aplicativo WPF (ou do Windows Forms).

    <PropertyGroup>
      <EnableTypeInfoReflection>false</EnableTypeInfoReflection>
      <EnableXBindDiagnostics>false</EnableXBindDiagnostics>
    </PropertyGroup>
    
  5. Clique com o botão direito do mouse no arquivo de projeto e selecione Recarregar Projeto.

  6. Exclua o arquivo padrão Class1.cs e adicione um novo item Controle de Usuário ao projeto.

  7. No arquivo XAML do controle de usuário, adicione o StackPanel a seguir como um filho do Grid padrão. Este exemplo adiciona um controle TextBlock e associa o atributo Text do controle ao campo XamlIslandMessage.

    <StackPanel Background="LightCoral">
        <TextBlock>This is a simple custom WinRT XAML control</TextBlock>
        <Rectangle Fill="Blue" Height="100" Width="100"/>
        <TextBlock Text="{x:Bind XamlIslandMessage}" FontSize="50"></TextBlock>
    </StackPanel>
    
  8. No arquivo code-behind do controle de usuário, adicione o campo XamlIslandMessage à classe de controle de usuário, conforme mostrado abaixo.

    public sealed partial class MyUserControl : UserControl
    {
        public string XamlIslandMessage { get; set; }
    
        public MyUserControl()
        {
            this.InitializeComponent();
        }
    }
    
  9. Compile o projeto de biblioteca de classes UWP.

  10. No projeto do WPF, clique com o botão direito do mouse no nó Dependências e adicione uma referência ao projeto de biblioteca de classes UWP.

  11. No projeto de aplicativo UWP que você configurou anteriormente, clique com o botão direito do mouse no nó Referências e adicione uma referência ao projeto de biblioteca de classes UWP.

  12. Recompile toda a solução e verifique se todos os projetos serão compilados com êxito.

Hospedar o controle WinRT XAML personalizado em seu aplicativo WPF

  1. No Gerenciador de Soluções, expanda o projeto do WPF e abra o arquivo MainWindow.xaml ou alguma outra janela na qual você deseja hospedar o controle personalizado.

  2. No arquivo XAML, adicione a declaração a seguir de namespace ao elemento <Window>.

    xmlns:xaml="clr-namespace:Microsoft.Toolkit.Wpf.UI.XamlHost;assembly=Microsoft.Toolkit.Wpf.UI.XamlHost"
    
  3. No mesmo arquivo, adicione o controle a seguir ao elemento <Grid>. Altere o atributo InitialTypeName para o nome totalmente qualificado do controle de usuário em seu projeto de biblioteca de classes UWP.

    <xaml:WindowsXamlHost InitialTypeName="UWPClassLibrary.MyUserControl" ChildChanged="WindowsXamlHost_ChildChanged" />
    
  4. Abra o arquivo code-behind e adicione o código a seguir à classe Window. Esse código define um manipulador de eventos ChildChanged que atribui o valor do campo XamlIslandMessage do controle personalizado UWP ao valor do campo WPFMessage no aplicativo WPF. Altere UWPClassLibrary.MyUserControl para o nome totalmente qualificado do controle de usuário em seu projeto de biblioteca de classes UWP.

    private void WindowsXamlHost_ChildChanged(object sender, EventArgs e)
    {
        // Hook up x:Bind source.
        global::Microsoft.Toolkit.Wpf.UI.XamlHost.WindowsXamlHost windowsXamlHost =
            sender as global::Microsoft.Toolkit.Wpf.UI.XamlHost.WindowsXamlHost;
        global::UWPClassLibrary.MyUserControl userControl =
            windowsXamlHost.GetUwpInternalObject() as global::UWPClassLibrary.MyUserControl;
    
        if (userControl != null)
        {
            userControl.XamlIslandMessage = this.WPFMessage;
        }
    }
    
    public string WPFMessage
    {
        get
        {
            return "Binding from WPF to UWP XAML";
        }
    }
    
  5. Compile e execute seu aplicativo e confirme se o controle de usuário UWP é exibido conforme o esperado.

Adicionar um controle da biblioteca WinUI 2 ao controle personalizado

Tradicionalmente, os controles XAML WinRT foram lançados como parte do sistema operacional Windows e disponibilizados para os desenvolvedores por meio do SDK do Windows. A biblioteca WinUI é uma abordagem alternativa, em que as versões atualizadas dos controles WinRT XAML do SDK do Windows são distribuídas em um pacote NuGet que não está vinculado às versões de SDK do Windows. Essa biblioteca também inclui novos controles que não fazem parte do SDK do Windows e da plataforma UWP padrão.

Esta seção demonstra como adicionar um controle XAML do WinRT da biblioteca WinUI 2 ao seu controle de usuário.

Observação

No momento, as Ilhas XAML dão suporte somente a controles de hospedagem da biblioteca WinUI 2. O suporte para controles de hospedagem da Biblioteca WinUI 3 será disponibilizado em uma versão posterior.

  1. No projeto do aplicativo da UWP, instale a versão de lançamento ou pré-lançamento mais recente do pacote NuGet Microsoft.UI.Xaml.

    Observação

    Se seu aplicativo da área de trabalho estiver empacotado em um pacote MSIX, será possível usar uma versão de pré-lançamento ou de lançamento do pacote NuGet Microsoft.UI.Xaml. Se seu aplicativo da área de trabalho não estiver empacotado usando MSIX, será necessário instalar uma versão de pré-lançamento do pacote NuGet Microsoft.UI.Xaml.

  2. No arquivo App.xaml deste projeto, adicione o elemento filho a seguir ao elemento <xaml:XamlApplication>.

    <Application.Resources>
        <XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" />
    </Application.Resources>
    

    Depois de adicionar esse elemento, o conteúdo do arquivo agora deve ser semelhante a este.

    <xaml:XamlApplication
        x:Class="MyUWPApp.App"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:xaml="using:Microsoft.Toolkit.Win32.UI.XamlHost"
        xmlns:local="using:MyUWPApp">
        <Application.Resources>
            <XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" />
        </Application.Resources>
    </xaml:XamlApplication>
    
  3. No projeto de biblioteca de classes UWP, instale a versão mais recente do pacote NuGet Microsoft.UI.Xaml (a mesma versão que você instalou no projeto do aplicativo UWP).

  4. No mesmo projeto, abra o arquivo XAML para o controle de usuário e adicione a declaração de namespace a seguir ao elemento <UserControl>.

    xmlns:winui="using:Microsoft.UI.Xaml.Controls"
    
  5. No mesmo arquivo, adicione um elemento <winui:RatingControl /> como um filho do <StackPanel>. Esse elemento adiciona uma instância da classe RatingControl da biblioteca WinUI. Depois de adicionar esse elemento, o <StackPanel> agora deve ficar com a aparência a seguir.

    <StackPanel Background="LightCoral">
        <TextBlock>This is a simple custom WinRT XAML control</TextBlock>
        <Rectangle Fill="Blue" Height="100" Width="100"/>
        <TextBlock Text="{x:Bind XamlIslandMessage}" FontSize="50"></TextBlock>
        <winui:RatingControl />
    </StackPanel>
    
  6. Compile e execute seu aplicativo e confirme se o novo controle de classificação é exibido conforme o esperado.

Empacotar o aplicativo

Opcionalmente, você pode empacotar o aplicativo WPF em um pacote MSIX para implantação. O MSIX é a tecnologia moderna de empacotamento de aplicativo para o Windows e se baseia em uma combinação das tecnologias de instalação MSI, .appx, App-V e ClickOnce.

As instruções a seguir mostram como empacotar todos os componentes da solução em um pacote MSIX usando o Projeto de Empacotamento de Aplicativo do Windows no Visual Studio 2019. Essas etapas serão necessárias apenas se você quiser empacotar o aplicativo WPF em um pacote MSIX.

Observação

Se você optar por não empacotar seu aplicativo em um pacote MSIX para implantação, os computadores que executam o aplicativo precisarão ter o Runtime do Visual C++ instalado.

  1. Adicione um novo Projeto de Empacotamento de Aplicativo do Windows à solução. Quando você criar o projeto, selecione a mesma Versão de destino e a Versão mínima que você selecionou para o projeto UWP.

  2. No projeto de empacotamento, clique com o botão direito do mouse no nó Aplicativos e escolha Adicionar referência. Na lista de projetos, selecione o projeto do WPF em sua solução e clique em OK.

    Observação

    Caso queira publicar seu aplicativo na Microsoft Store, será necessário adicionar uma referência ao projeto UWP no projeto de empacotamento.

  3. Configure sua solução para destino a uma plataforma específica, como x86 ou x64. Isso é necessário para compilar o aplicativo WPF em um pacote MSIX usando o Projeto de Empacotamento de Aplicativo do Windows.

    1. No Gerenciador de Soluções, clique com o botão direito do mouse no nó da solução e selecione Propriedades>Propriedades de Configuração>Gerenciador de Configurações.
    2. Em Plataforma da solução ativa, selecione x64 ou x86.
    3. Na linha do seu projeto do WPF, na coluna Plataforma, selecione Nova.
    4. Na caixa de diálogo Nova Plataforma de Solução, selecione x64 ou x86 (a mesma plataforma selecionada em Plataforma de solução ativa) e clique em OK.
    5. Feche as caixas de diálogo abertas.
  4. Compile e execute o projeto de empacotamento. Confirme se o WPF é executado e se o controle personalizado UWP é exibido conforme o esperado.

  5. Para obter informações sobre como distribuir/implantar o pacote, consulte Gerenciar sua implantação MSIX.

Resolver o erro "Não é possível encontrar um recurso" ao hospedar um controle WinUI

Caso você hospede um controle personalizado que contém um controle da Biblioteca WinUI, talvez encontre um problema em que o controle não pode ser carregado em um aplicativo empacotado e o código de depuração mostra o erro a seguir.

Falha ao hospedar o controle da Biblioteca WinUI

Para resolver esse erro, copie o arquivo App.xbf da pasta de saída da compilação do projeto do WPF para a pasta de saída da compilação do projeto do WPF <\AppX\> do projeto de empacotamento.

Por exemplo, se o projeto do WPF tiver o nome WPFXamlIslandsApp e for direcionado para a plataforma x86, copie App.xbf de \WPFXamlIslandsApp\bin\x86\Release\netcoreapp3.1 para \WPFXamlIslandsApp.Pack\bin\x86\Release\AppX\WPFXamlIslandsAPP.