Passo a passo — Criar um componente C# com controles WinUI 3 e consumi-lo de um aplicativo C++/WinRT que usa o SDK do Aplicativo Windows

O C#/WinRT fornece suporte para criação de componentes Windows Runtime, incluindo tipos personalizados da WinUI e controles personalizados. Esses componentes podem ser consumidos de aplicativos C# ou C++/WinRT que usam o SDK do Aplicativo Windows. É recomendável usar o C#/WinRT v1.6.4 ou posterior para criar componentes de runtime com NuGet suporte ao empacotamento.

Para obter mais detalhes sobre os cenários com suporte, consulte os componentes C#/WinRT de criação no repositório de GitHub do C#/WinRT.

Este passo a passo demonstra como criar um componente C# com um controle da WinUI 3 personalizado e como consumir esse componente de um aplicativo C++/WinRT, usando os modelos de projeto de SDK do Aplicativo Windows.

Pré-requisitos

Este tutorial exige os seguintes componentes e ferramentas:

Crie seu componente C#/WinRT usando o SDK do Aplicativo Windows

  1. Crie um novo projeto de biblioteca em C# usando o modelo de Biblioteca de Classes (WinUI 3 na Área de Trabalho) fornecido pelo SDK do Aplicativo Windows. Para este passo a passo, nomeamos o projeto de biblioteca WinUIComponentCs e a solução AuthoringWinUI.

    Deixe a Posicionar solução e projeto no mesmo diretório desmarcados (caso contrário, a packages pasta do aplicativo C++ na seção anterior acabará interferindo no projeto da biblioteca C#).

    New library dialog

  2. Exclua o arquivo Class1.cs incluído por padrão.

  3. Instale o microsoft.Windows mais recente. CsWinRT pacote de NuGet em seu projeto.

    i. No Gerenciador de Soluções, clique com o botão direito do mouse no nó do projeto e selecione Gerenciar pacotes de NuGet.

    ii. Pesquise pelo pacote de NuGet Microsoft.Windows.CsWinRT e instale a versão mais recente.

  4. Adicione as seguintes propriedades ao projeto de biblioteca:

    <PropertyGroup>   
        <CsWinRTComponent>true</CsWinRTComponent>
    </PropertyGroup>
    
    • A propriedade CsWinRTComponent especifica que seu projeto é um componente do Windows Runtime, para que um arquivo .winmd seja gerado ao compilar o projeto.
  5. Adicione um controle personalizado ou controle de usuário à biblioteca. Para fazer isso, clique com o botão direito do mouse em seu projeto em Visual Studio, clique em Adicionar>Novo Item e selecione WinUI no painel esquerdo. Para este passo a passo, adicionamos um novo Controle de Usuário (WinUI 3) e o nomeamos NameReporter.xaml. O controle de usuário NameReporter permite que um usuário insira um nome e sobrenome no controle TextBox apropriado e clique em um botão. Em seguida, o controle exibe uma caixa de mensagem com o nome que o usuário inseriu.

  6. Cole o seguinte código no arquivo NameReporter.xaml:

    <UserControl
    x:Class="WinUIComponentCs.NameReporter"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:WinUIComponentCs"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">
    
        <StackPanel HorizontalAlignment="Center">
            <StackPanel.Resources>
                <Style x:Key="BasicTextStyle" TargetType="TextBlock" BasedOn="{StaticResource BodyTextBlockStyle}">
                    <Setter Property="Margin" Value="10,10,10,10"/>
                </Style>
            </StackPanel.Resources>
    
            <TextBlock Text="Enter your name." Margin="0,0,0,10"/>
            <StackPanel Orientation="Horizontal" Margin="0,0,0,10">
                <TextBlock Style="{StaticResource BasicTextStyle}">
                    First Name:
                </TextBlock>
                <TextBox Name="firstName" />
            </StackPanel>
            <StackPanel Orientation="Horizontal" Margin="0,0,0,10">
                <TextBlock Style="{StaticResource BasicTextStyle}">
                    Last Name:
                </TextBlock>
                <TextBox Name="lastName" />
            </StackPanel>
            <Button Content="Submit" Click="Button_Click" Margin="0,0,0,10"/>
            <TextBlock Name="result" Style="{StaticResource BasicTextStyle}" Margin="0,0,0,10"/>
        </StackPanel>
    </UserControl>
    
  7. Adicione o seguinte método a NameReporter.xaml.cs:

    using System.Text;
    ...
    private void Button_Click(object sender, RoutedEventArgs e)
    {
        StringBuilder displayText = new StringBuilder("Hello, ");
        displayText.AppendFormat("{0} {1}.", firstName.Text, lastName.Text);
        result.Text = displayText.ToString();
    }
    
  8. Agora é possível compilar o projeto WinUIComponentCs para gerar um arquivo .winmd para o componente.

Observação

Você também pode empacotar o componente como um pacote de NuGet para que os consumidores de aplicativos finais façam referência. Para obter mais detalhes, consulte Criação de componentes C#/WinRT no repositório de Github do C#/WinRT.

Referenciar o componente de um aplicativo C++/WinRT do SDK do Aplicativo Windows

As etapas a seguir mostram como consumir o componente criado da seção anterior de um aplicativo C++/WinRT do SDK do Aplicativo Windows. Consumir um componente C#/WinRT do C++ atualmente requer o uso do modelo aplicativo em branco de projeto único, empacotado (WinUI 3 na Área de Trabalho). Observe que os componentes C# também podem ser referenciados de aplicativos empacotados em C# sem registros de classe.

Atualmente, não há suporte para o consumo de aplicativos empacotados que usam um projeto WAP (Empacotamento de Aplicativo do Windows) separado. Consulte a criação de componentes de C#/WinRT no repositório de GitHub do C#/WinRT para obter as atualizações mais recentes sobre as configurações de projeto com suporte.

  1. Adicione um novo projeto de aplicativo C++ do SDK do Aplicativo Windows à sua solução. Clique com o botão direito do mouse em sua solução no Visual Studio e selecione Adicionar>Novo Project. Selecione o modelo C++ Blank App, Empacotado (WinUI 3 na Área de Trabalho) fornecido pelo SDK do Aplicativo Windows. Para este passo a passo, nomeamos o aplicativo CppApp.

  2. Adicione uma referência de projeto do aplicativo C++ ao componente C#. Em Visual Studio, clique com o botão direito do mouse no projeto C++ e escolha Adicionar>Referência e selecione o projeto WinUIComponentCs.

    Observação

    Há suporte para o consumo de componentes como uma referência de pacote de NuGet com algumas limitações. Ou seja, os componentes com controles de usuário personalizados não podem ser consumidos atualmente como uma referência de pacote de NuGet.

  3. No arquivo de cabeçalho do aplicativo pch.h, adicione as seguintes linhas:

    #include <winrt/WinUIComponentCs.h>
    #include <winrt/WinUIComponentCs.WinUIComponentCs_XamlTypeInfo.h>
    
  4. Abra o arquivo de manifesto do pacote, Package.appxmanifest.

    Observação

    Há um problema conhecido em que o arquivo Package.appxmanifest não aparece em Gerenciador de Soluções do Visual Studio. Para solucionar isso, clique com o botão direito do mouse em seu projeto C++, selecione Descarregar Project e clique duas vezes no projeto para abrir o arquivo CppApp.vcxproj. Adicione a seguinte entrada ao arquivo de projeto e recarregue o projeto:

    <ItemGroup>
        <AppxManifest Include="Package.appxmanifest">
        <SubType>Designer</SubType>
        </AppxManifest>
    </ItemGroup>
    

    In Package.appxmanifest, adicione os seguintes registros de classe ativantes. Você também precisará de uma entrada adicional ActivatableClass para a classe WinUIComponentCs.WinUIComponentCs_XamlTypeInfo.XamlMetaDataProvider para ativar os tipos de WinUI. Clique com o botão direito do Package.appxmanifest mouse no arquivo e selecione Abrir com>XML (Editor de Texto) para editar o arquivo.

    <!--In order to host the C# component from C++, you must add the following Extension group and list the activatable classes-->
    <Extensions>
        <Extension Category="windows.activatableClass.inProcessServer">
            <InProcessServer>
                <Path>WinRT.Host.dll</Path>
                <ActivatableClass ActivatableClassId="WinUIComponentCs.NameReporter" ThreadingModel="both" />
                <ActivatableClass ActivatableClassId="WinUIComponentCs.WinUIComponentCs_XamlTypeInfo.XamlMetaDataProvider" ThreadingModel="both" />
            </InProcessServer>
        </Extension>
    </Extensions>
    
  5. Abra o arquivo MainWindow.xaml.

    i. Adicione uma referência ao namespace do componente na parte superior do arquivo.

    xmlns:custom="using:WinUIComponentCs"
    

    ii. Adicione o controle de usuário ao código XAML existente.

    <StackPanel>
        ...
        <custom:NameReporter/>
    </StackPanel>
    
  6. Defina o CppApp como o projeto de inicialização, clique com o botão direito do mouse no CppApp e selecione Definir como Project de Inicialização. Defina a configuração da solução para x86. Antes de criar, talvez você também precise redirecionar sua solução para compilar com as ferramentas de compilação do Visual Studio 2022. Clique com o botão direito do mouse na solução, selecione a Solução de redirecionamento e atualize o Conjunto de Ferramentas de Plataforma para v143.

  7. Compile e execute o aplicativo para ver o controle NameReporter personalizado.

Problemas conhecidos

  • Consumir um componente C# como uma referência de projeto requer PublishReadyToRun ser definido como False. Confira o Problema do Github nº 1151 para obter mais detalhes.
  • O consumo de um componente C# criado a AnyCPU partir do C++ só tem suporte de x86 aplicativos no momento. x64 e Arm64 aplicativos resultam em um erro de runtime semelhante a: %1 não é um aplicativo Win32 válido. Consulte o Problema do Github nº 1151 para obter mais detalhes.