Usar as ilhas XAML para hospedar um controle XAML da UWP em um aplicativo WPF em C#

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 tópico mostra como criar um aplicativo WPF (Windows Presentation Foundation) em C# (direcionado ao .NET Core 3.1) que usa ilhas XAML para hospedar um controle XAML da UWP (Plataforma Universal do Windows) (ou seja, um controle primário fornecido pelo SDK do Windows). Para isso, há duas opções:

  • Você verá como hospedar controles de InkCanvas e de InkToolbar da UWP usando controles encapsulados (disponíveis no Windows Community Toolkit). Esses controles encapsulam a interface e a funcionalidade de um pequeno conjunto de controles XAML úteis da UWP. É possível adicionar esses controles encapsulados diretamente ao Design Surface do projeto do WPF ou do Windows Forms e usá-los como qualquer outro controle do WPF ou do Windows Forms no designer.

  • Você também verá como hospedar um controle de CalendarView da UWP usando o controle de WindowsXamlHost (disponível no Windows Community Toolkit). Como apenas um pequeno conjunto de controles da UWP está disponível na forma de controles encapsulados, é possível usar o WindowsXamlHost para hospedar qualquer controle XAML da UWP.

O processo para hospedar um controle XAML da UWP em um aplicativo WPF é semelhante para um aplicativo Windows Forms.

Importante

O uso de ilhas XAML (controles encapsulados ou de WindowsXamlHost) para hospedar controles XAML da UWP tem suporte apenas em aplicativos destinados ao .NET Core 3.x. As ilhas XAML não têm suporte em aplicativos destinados ao .NET nem em aplicativos destinados a qualquer versão do .NET Framework.

Para hospedar um controle XAML da UWP em um aplicativo WPF ou Windows Forms, recomenda-se ter os componentes a seguir na solução. Este artigo fornece instruções para criar cada um desses componentes:

  • O projeto e o código-fonte do aplicativo WPF ou Windows Forms.

  • Um projeto da UWP que define uma classe de aplicativo raiz derivada de XamlApplication. A classe Microsoft.Toolkit.Win32.UI.XamlHost.XamlApplication está disponível no Windows Community Toolkit. Recomenda-se definir a classe de aplicativo derivada de XamlApplication como um projeto de aplicativo da UWP separado que faz parte da solução Visual Studio do WPF ou do Windows Forms.

    Observação

    Não é realmente necessário tornar um objeto derivado de XamlApplication disponível para o projeto do WPF ou do Windows Forms a fim de hospedar um controle XAML primário da UWP. No entanto, isso é necessário para descobrir, carregar e hospedar controles XAML personalizados da UWP. Assim, para dar suporte à gama completa de cenários de ilhas XAML, recomenda-se sempre definir um objeto derivado de XamlApplication em qualquer solução em que elas sejam usadas.

    Observação

    Sua solução só pode conter um projeto que define um objeto derivado de XamlApplication. Esse projeto deve referenciar quaisquer bibliotecas e projetos que hospedem controles XAML da UWP por meio de ilhas XAML.

Criar um projeto do WPF

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, adapte essas etapas e exemplos de código para ele.

  1. Caso você ainda não tenha instalado a versão mais recente do .NET Core 3.1, faça isso.

  2. No Visual Studio, crie um projeto em C# por meio do modelo de projeto de Aplicativo WPF. Defina o Nome do projeto como MyWPFApp para que você não precise editar nenhuma das etapas ou do código-fonte neste tópico. Defina a Estrutura como .NET Core 3.1* e clique em Criar.

Importante

Não use o modelo de projeto de Aplicativo WPF (.NET Framework).

Configurar seu projeto do WPF

  1. Estas etapas habilitam as referências de pacote:

    1. No Visual Studio, clique em Ferramentas>Gerenciador de Pacotes NuGet>Configurações do Gerenciador de Pacotes.
    2. À direita, localize a configuração Gerenciamento de Pacotes>Formato padrão de gerenciamento de pacotes e defina-a como PackageReference.
  2. Siga estas etapas para instalar o pacote NuGet Microsoft.Toolkit.Wpf.UI.Controls:

    1. Clique com o botão direito do mouse no nó do projeto MyWPFApp no Gerenciador de Soluções e escolha Gerenciar pacotes NuGet....

    2. Na guia Procurar, digite ou cole Microsoft.Toolkit.Wpf.UI.Controls na caixa de pesquisa. Selecione a versão estável mais recente e clique em Instalar. O pacote fornece tudo o que você precisa para usar os controles XAML encapsulados da UWP para o WPF (incluindo InkCanvas, InkToolbar e o controle de WindowsXamlHost).

    Observação

    Para um aplicativo Windows Forms, referencie o pacote Microsoft.Toolkit.Forms.UI.Controls como alternativa.

  3. A maioria dos cenários de ilhas XAML não é compatível com projetos destinados a Qualquer CPU. Portanto, para ter uma arquitetura específica como destino (como x86 ou x64), faça o seguinte:

    1. Clique com o botão direito do mouse no nó da solução (não no nó do projeto) em Gerenciador de Soluções e escolha Propriedades.
    2. Selecione Propriedades de configuração à esquerda.
    3. Clique no botão Configuration Manager....
    4. Em Plataforma da solução ativa, selecione Nova.
    5. Na caixa de diálogo Nova plataforma de solução, selecione x64 ou x86 e pressione OK.
    6. Feche as caixas de diálogo abertas.

Definir uma classe XamlApplication em um novo projeto da UWP

Nesta seção, você adicionará um projeto da UWP à solução e revisará a classe de Aplicativo padrão no 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 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. Selecione o modelo de projeto em C# Aplicativo em branco (Universal do Windows). Defina o Nome do projeto como MyUWPApp para que você não precise editar nenhuma das etapas ou do código-fonte neste tópico. Defina a Versão de destino e a Versão mínima como Windows 10, versão 1903 (Build 18362) ou posterior.

    Observação

    Certifique-se de não criar MyUWPApp em uma subpasta de MyWPFApp. Se você fizer isso, o MyWPFApp tentará criar a marcação XAML da UWP como um XAML do WPF.

  3. No MyUWPApp, instale o pacote NuGet Microsoft.Toolkit.Win32.UI.XamlApplication (versão estável mais recente). O processo de instalação de um pacote NuGet foi descrito na seção anterior.

  4. No MyUWPApp, abra o arquivo App.xaml e substitua o conteúdo dele pelo seguinte XAML:

    <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. Da mesma forma, abra App.xaml.cs e substitua o conteúdo dele pelo seguinte código:

    namespace MyUWPApp
    {
        public sealed partial class App : Microsoft.Toolkit.Win32.UI.XamlHost.XamlApplication
        {
            public App()
            {
                this.Initialize();
            }
        }
    }
    
  6. Exclua os arquivos MainPage.xaml e MainPage.xaml.cs.

  7. Compile o projeto MyUWPApp.

No MyWPFApp, adicione uma referência ao projeto MyUWPApp

  1. Especifique a versão de estrutura compatível no arquivo de projeto do MyWPFApp da seguinte forma:

    1. No Gerenciador de Soluções, clique no nó do projeto MyWPFApp 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 sistema operacional de destino e mínimo do projeto MyWPFApp.

      <AssetTargetFallback>uap10.0.19041</AssetTargetFallback>
      
  2. Em Gerenciador de Soluções, clique com o botão direito do mouse em MyWPFApp>Dependências, escolha Adicionar Referência de Projeto... e adicione uma referência ao projeto MyUWPApp.

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

Em seguida, adicione o código ao ponto de entrada de MyWPFApp para criar uma instância da classe de aplicativo que você acabou de definir em MyUWPApp (a classe que deriva de XamlApplication).

  1. Clique com o botão direito do mouse no nó do projeto MyWPFApp, selecione Adicionar>Novo item... e escolha Classe. Defina Nome como Program.cs e clique em Adicionar.

  2. Substitua o conteúdo de Program.cs pelo seguinte XAML e, em seguida, salve o arquivo e compile o projeto MyWPFApp:

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

  4. Em Aplicativo>Geral, clique na lista suspensa Objeto de inicialização e escolha MyWPFApp.Program (que é o nome totalmente qualificado da classe Programa que você acabou de adicionar). Se você não encontrar a opção, tente fechar e reabrir o Visual Studio.

    Observação

    Por padrão, um projeto do WPF define 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 projeto para o método Main da nova classe Programa, o que permite que você adicione um código que é executado o mais cedo possível no processo de inicialização do aplicativo.

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

Usar controles encapsulados para hospedar um InkCanvas e um InkToolbar

Agora que você configurou o projeto para usar as ilhas XAML da UWP, está pronto para adicionar os controles XAML encapsulados de InkCanvas e de InkToolbar da UWP ao aplicativo.

  1. No MyWPFApp, abra o arquivo MainWindow.xaml.

  2. No elemento Window próximo à parte superior do arquivo XAML, adicione o atributo a seguir. Esse atributo faz referência ao namespace de XAML dos controles XAML encapsulados de InkCanvas e de InkToolbar da UWP e o mapeia para o namespace de XML de controles.

    xmlns:controls="clr-namespace:Microsoft.Toolkit.Wpf.UI.Controls;assembly=Microsoft.Toolkit.Wpf.UI.Controls"
    
  3. Ainda em MainWindow.xaml, edite o elemento de Grade existente para que ele se pareça com o XAML abaixo. Esse XAML adiciona um controle de InkCanvas e de InkToolbar à Grade (prefixado pelo namespace de XML de controles que você definiu na etapa anterior).

    <Grid Margin="10,50,10,10">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <controls:InkToolbar x:Name="myInkToolbar" TargetInkCanvas="{x:Reference myInkCanvas}" Grid.Row="0" Width="300"
            Height="50" Margin="10,10,10,10" HorizontalAlignment="Left" VerticalAlignment="Top" />
        <controls:InkCanvas x:Name="myInkCanvas" Grid.Row="1" HorizontalAlignment="Left" Width="600" Height="400"
            Margin="10,10,10,10" VerticalAlignment="Top" />
    </Grid>
    

    Observação

    Também é possível adicionar esses e outros controles encapsulados à Janela arrastando-os da seção Windows Community Toolkit da Caixa de ferramentas para o designer.

  4. Salvar MainWindow.xaml.

    Se você tiver um dispositivo compatível com uma caneta digital, como um Surface, e estiver executando esse laboratório em um computador físico, será possível criar e executar o aplicativo e desenhar com tinta digital na tela usando a caneta. No entanto, se você tentar escrever com o mouse, nada acontecerá, pois o InkCanvas só está habilitado por padrão para canetas digitais. Veja como habilitar o InkCanvas para o mouse.

  5. Ainda no MyWPFApp, abra MainWindow.xaml.cs.

  6. Adicione a seguinte diretiva de namespace à parte superior do arquivo:

    using Microsoft.Toolkit.Win32.UI.Controls.Interop.WinRT;
    
  7. Localize o construtor MainWindow. Imediatamente após a chamada para InitializeComponent, adicione a seguinte linha de código:

    myInkCanvas.InkPresenter.InputDeviceTypes = CoreInputDeviceTypes.Mouse | CoreInputDeviceTypes.Pen;
    

    Você pode usar o objeto InkPresenter para personalizar a experiência de tinta padrão. Esse código usa a propriedade InputDeviceTypes para habilitar o mouse e a entrada à caneta.

  8. Faça o salvamento, o build e execute-o. Se você estiver usando um computador com um mouse, veja se é possível desenhar algo com ele no espaço da tela destinado à tinta.

Hospedar um CalendarView usando o controle de host

Nesta seção, você usará o controle de WindowsXamlHost para adicionar um CalendarView ao aplicativo.

Observação

O controle de WindowsXamlHost é fornecido pelo pacote Microsoft.Toolkit.Wpf.UI.XamlHost. Esse pacote está incluído no pacote Microsoft.Toolkit.Wpf.UI.Controls que você instalou anteriormente.

  1. Em Gerenciador de Soluções, no MyWPFApp, abra o arquivo MainWindow.xaml.

  2. No elemento Window próximo à parte superior do arquivo XAML, adicione o atributo a seguir. Esse atributo faz referência ao namespace de XAML do controle de WindowsXamlHost e o mapeia para o namespace de XML xamlhost.

    xmlns:xamlhost="clr-namespace:Microsoft.Toolkit.Wpf.UI.XamlHost;assembly=Microsoft.Toolkit.Wpf.UI.XamlHost"
    
  3. Ainda em MainWindow.xaml, edite o elemento de Grade existente para que ele se pareça com o XAML abaixo. Esse XAML adiciona um controle de WindowsXamlHost à Grade (prefixado pelo namespace de XML xamlhost que você definiu na etapa anterior). Para hospedar um controle de CalendarView da UWP, esse XAML define a propriedade InitialTypeName com o nome totalmente qualificado do controle. Ele também define um manipulador de eventos para o evento ChildChanged, que é gerado quando o controle hospedado é renderizado.

    <Grid Margin="10,50,10,10">
        <xamlhost:WindowsXamlHost x:Name="myCalendar" InitialTypeName="Windows.UI.Xaml.Controls.CalendarView"
              Margin="10,10,10,10" Width="600" Height="300" ChildChanged="MyCalendar_ChildChanged" />
    </Grid>
    
  4. Salve MainWindow.xaml e abra MainWindow.xaml.cs.

  5. Exclua essa linha de código, que foi adicionada na seção anterior: myInkCanvas.InkPresenter.InputDeviceTypes = CoreInputDeviceTypes.Mouse | CoreInputDeviceTypes.Pen;.

  6. Adicione a seguinte diretiva de namespace à parte superior do arquivo:

    using Microsoft.Toolkit.Wpf.UI.XamlHost;
    
  7. Adicione o método do manipulador de eventos ChildChanged a seguir à classe MainWindow. Quando o controle de host for renderizado, o manipulador de eventos será executado e criará um manipulador de eventos simples para o evento SelectedDatesChanged do controle de calendário.

    private void MyCalendar_ChildChanged(object sender, EventArgs e)
    {
        WindowsXamlHost windowsXamlHost = (WindowsXamlHost)sender;
    
        var calendarView =
            (Windows.UI.Xaml.Controls.CalendarView)windowsXamlHost.Child;
    
        if (calendarView != null)
        {
            calendarView.SelectedDatesChanged += (obj, args) =>
            {
                if (args.AddedDates.Count > 0)
                {
                    MessageBox.Show("The user selected a new date: " +
                        args.AddedDates[0].DateTime.ToString());
                }
            };
        }
    }
    
  8. Faça o salvamento, o build e execute-o. Verifique se o controle de calendário é mostrado na janela e se uma caixa de mensagem é exibida quando você seleciona uma data.

Empacotar o aplicativo

Opcionalmente, empacote o aplicativo WPF em um pacote MSIX para implantação. O MSIX é a tecnologia moderna e confiável de empacotamento de aplicativos para Windows.

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 (veja Configurar seu aplicativo de área de trabalho para o empacotamento MSIX no Visual Studio). Essas etapas serão necessárias apenas se você quiser empacotar o aplicativo WPF em um pacote MSIX.

Observação

Ao optar por não empacotar o aplicativo em um pacote MSIX para implantação, deve-se instalar o Runtime do Visual C++ nos computadores que o executam.

  1. Adicione um projeto à solução criada por meio do modelo de projeto do Projeto de Empacotamento de Aplicativo do Windows. 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ó Dependências e escolha Adicionar Referência de Projeto.... Na lista de projetos, selecione MyWPFApp e clique em OK.

    Observação

    Para publicar o aplicativo na Microsoft Store, é necessário adicionar uma referência ao projeto da UWP no projeto de empacotamento.

  3. Se você seguiu as etapas até agora, todos os projetos na solução serão destinados à mesma plataforma específica (x86 ou x64). Isso é necessário para compilar o aplicativo WPF em um pacote MSIX usando o Projeto de Empacotamento de Aplicativo do Windows. Siga estas etapas para confirmar:

    1. Clique com o botão direito do mouse no nó da solução (não no nó do projeto) em Gerenciador de Soluções e escolha Propriedades.
    2. Selecione Propriedades de configuração à esquerda.
    3. Clique no botão Configuration Manager....
    4. Verifique se todos os projetos listados têm o mesmo valor em Plataforma: x86 ou x64.
  4. Clique com o botão direito do mouse no nó do projeto de empacotamento que você acabou de adicionar e selecione Definir como projeto de inicialização.

  5. Compile e execute o projeto de empacotamento. Confirme se o WPF está em execução e se o controle da UWP está sendo exibido conforme o esperado.

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