Criar um aplicativo "Olá, Mundo!" Aplicativo UWP usando C++/WinRT

Este tópico explica como criar um aplicativo UWP (Plataforma Universal do Windows) "Olá, Mundo!" do Windows usando C++/WinRT. A interface do usuário do aplicativo é definida usando XAML (Extensible Application Markup Language).

O C++/WinRT é uma projeção da linguagem C++17 moderna e inteiramente padrão para APIs do WinRT (Windows Runtime). Para obter mais informações, mais guias passo a passo e exemplos de código, confira a documentação do C++/WinRT. Um bom tópico para começar é Introdução ao C++/WinRT.

Configurar o Visual Studio Code para C++/WinRT

Para saber mais sobre como configurar o Visual Studio para desenvolvimento em C++/WinRT, incluindo instalação e uso da VSIX (Extensão do Visual Studio) para C++/WinRT e o pacote NuGet (que juntos fornecem um modelo de projeto e suporte ao build), confira Suporte do Visual Studio para C++/WinRT.

Para baixar o Visual Studio, confira Downloads.

Para obter uma introdução ao XAML, confira Visão geral do XAML

Criar um aplicativo em branco (HelloWorldCppWinRT)

Nosso primeiro aplicativo é um aplicativo "Hello World" que demonstra alguns recursos básicos de interatividade, layout e estilos.

Comece criando um novo projeto no Microsoft Visual Studio. Crie um projeto Aplicativo em Branco (C++/WinRT) e chame-o de HelloWorldCppWinRT. Verifique se a opção Colocar a solução e o projeto no mesmo diretório está desmarcada. Direcione a versão mais recente em disponibilidade geral (ou seja, que não esteja em versão prévia) do SDK do Windows.

Em uma seção posterior deste tópico, você será direcionado para criar seu projeto (mas não o crie até lá).

Sobre os arquivos do projeto

Normalmente, na pasta do projeto, cada arquivo .xaml (marcação XAML) tem um arquivo .idl, .h e .cpp correspondente. Juntos, esses arquivos são compilados em um tipo de página XAML.

Você pode modificar um arquivo de marcação XAML para criar elementos de interface do usuário e associá-los a fontes de dados (uma tarefa conhecida como associação de dados). Você modifica os arquivos .h e .cpp (e, às vezes, o arquivo .idl) para adicionar lógica personalizada à página XAML – manipuladores de evento, por exemplo.

Vamos examinar os arquivos de projeto.

  • App.idl, App.xaml, App.h e App.cpp. Esses arquivos representam a especialização do seu aplicativo da classe Windows::UI::XAML::Application, que inclui o ponto de entrada do aplicativo. App.xaml não contém nenhuma marcação específica de página, mas você pode adicionar estilos de elemento de interface do usuário lá, bem como outros elementos que você queira que possam ser acessados de todas as páginas. Os arquivos .h e .cpp contêm manipuladores para vários eventos de ciclo de vida do aplicativo. Normalmente, você adiciona o código personalizado lá para inicializar o aplicativo quando ele iniciar e executar a limpeza quando ele for suspenso ou encerrado.
  • MainPage.idl, MainPage.xaml, MainPage.h e MainPage.cpp. Contém a marcação XAML e a implementação para o tipo de página principal (de inicialização) padrão em um aplicativo, que é a classe de runtime MainPage. MainPage não tem suporte de navegação, mas fornece alguma interface do usuário padrão e um manipulador de eventos para você começar.
  • pch.h e pch.cpp. Esses arquivos representam o arquivo de cabeçalho pré-compilado do projeto. No pch.h, inclua todos os arquivos de cabeçalho que não são alterados com frequência e, em seguida, inclua pch.h em outros arquivos no projeto.

Primeira análise do código

classes de runtime

Como você deve saber, todas as classes em um aplicativo UWP (Plataforma Universal do Windows) escrito em C# são tipos do Windows Runtime. Todavia, quando você cria um tipo em um aplicativo C++/WinRT, é possível escolher se esse tipo é do Windows Runtime ou de uma classe/struct/enumeração C++ regular.

Qualquer tipo de página XAML em seu projeto precisa ser um tipo do Windows Runtime. Portanto, MainPage é um tipo do Windows Runtime. Especificamente, é uma classe de runtime. Um tipo consumido por uma página XAML também precisa ser um tipo do Windows Runtime. Quando você estiver escrevendo um componente do Windows Runtime e desejar criar um tipo que possa ser consumido de outro aplicativo, você criará um tipo do Windows Runtime. Em outros casos, seu tipo pode ser um tipo C++ regular. Em geral, um tipo do Windows Runtime pode ser consumido usando qualquer linguagem do Windows Runtime.

Uma boa indicação de que um tipo é um tipo do Windows Runtime é que ele é definido na linguagem IDL da Microsoft dentro de um arquivo .idl (Linguagem de Definição de Interface). Vamos usar MainPage como um exemplo.

// MainPage.idl
namespace HelloWorldCppWinRT
{
    [default_interface]
    runtimeclass MainPage : Windows.UI.Xaml.Controls.Page
    {
        MainPage();
        Int32 MyProperty;
    }
}

Esta é a estrutura básica da implementação da classe de runtime MainPage e a fábrica de ativação dela, como visto em MainPage.h.

// MainPage.h
...
namespace winrt::HelloWorldCppWinRT::implementation
{
    struct MainPage : MainPageT<MainPage>
    {
        MainPage();

        int32_t MyProperty();
        void MyProperty(int32_t value);
        ...
    };
}

namespace winrt::HelloWorldCppWinRT::factory_implementation
{
    struct MainPage : MainPageT<MainPage, implementation::MainPage>
    {
    };
}

Para obter mais detalhes sobre se você deve ou não criar uma classe de runtime para um determinado tipo, confira o tópico Criar APIs com C++/WinRT. E, para obter mais informações sobre a conexão entre classes de runtime e a IDL (arquivos .idl), leia e acompanhe o tópico Controles XAML; associar a uma propriedade de C++/WinRT. Esse tópico aborda o processo de criação de uma classe de runtime, cuja primeira etapa é adicionar um novo item Midl File (.idl) ao projeto.

Agora, vamos adicionar alguma funcionalidade ao projeto HelloWorldCppWinRT.

Etapa 1. Modificar sua página de inicialização

Em Gerenciador de Soluções, abra MainPage.xaml para poder criar os controles que formam a interface do usuário.

Exclua o StackPanel que já existe, bem como o conteúdo dele. No lugar, cole o XAML a seguir.

<StackPanel x:Name="contentPanel" Margin="120,30,0,0">
    <TextBlock HorizontalAlignment="Left" Text="Hello, World!" FontSize="36"/>
    <TextBlock Text="What's your name?"/>
    <StackPanel x:Name="inputPanel" Orientation="Horizontal" Margin="0,20,0,20">
        <TextBox x:Name="nameInput" Width="300" HorizontalAlignment="Left"/>
        <Button x:Name="inputButton" Content="Say &quot;Hello&quot;"/>
    </StackPanel>
    <TextBlock x:Name="greetingOutput"/>
</StackPanel>

Esse novo StackPanel tem um TextBlock que solicita o nome do usuário, um TextBox que aceita o nome do usuário, um Button e outro elemento TextBlock.

Como excluímos o Botão denominado myButton, precisaremos remover a referência a ele do código. Portanto, em MainPage.cpp, exclua a linha de código dentro da função MainPage::ClickHandler.

Neste ponto, você criou um Aplicativo Universal do Windows muito básico. Para ver a aparência do aplicativo UWP, compile e execute o aplicativo.

Tela do aplicativo UWP com controles

Nele, você pode digitar na caixa de texto. Mas clicar no botão não faz nada ainda.

Etapa 2. Adicionar um manipulador de eventos

Em MainPage.xaml, localize o Botão chamado inputButton e declare um manipulador de eventos para o evento ButtonBase::Click dele. A marcação do Botão agora deve ter esta aparência.

<Button x:Name="inputButton" Content="Say &quot;Hello&quot;" Click="inputButton_Click"/>

Implemente o manipulador de eventos como este.

// MainPage.h
struct MainPage : MainPageT<MainPage>
{
    ...
    void inputButton_Click(
        winrt::Windows::Foundation::IInspectable const& sender,
        winrt::Windows::UI::Xaml::RoutedEventArgs const& e);
};

// MainPage.cpp
namespace winrt::HelloWorldCppWinRT::implementation
{
    ...
    void MainPage::inputButton_Click(
        winrt::Windows::Foundation::IInspectable const& sender,
        winrt::Windows::UI::Xaml::RoutedEventArgs const& e)
    {
        greetingOutput().Text(L"Hello, " + nameInput().Text() + L"!");
    }
}

Para obter mais informações, confira Manipular eventos usando delegados.

A implementação recupera o nome do usuário da caixa de texto, usa-o para criar uma saudação e exibe isso no bloco de texto greetingOutput.

Compile e execute o aplicativo. Digite seu nome na caixa de texto e clique no botão. O aplicativo exibe uma saudação personalizada.

Tela do aplicativo com exibição da mensagem

Etapa 3. Estilizar a página de inicialização

Escolher um tema

É fácil personalizar a aparência do aplicativo. Por padrão, seu aplicativo usa recursos que têm um estilo com cores claras. Os recursos do sistema também incluem um tema escuro.

Para experimentar o tema escuro, edite App.xaml e adicione um valor para Application:RequestedTheme.

<Application
    ...
    RequestedTheme="Dark">

</Application>

Para aplicativos que exibem sobretudo imagens ou vídeo, recomendamos o uso do tema escuro. Já para aplicativos que contêm muito texto, recomendamos o uso do tema claro. Se você estiver usando um esquema de cores personalizado, então use o tema que combina melhor com a aparência do seu aplicativo.

Observação

Um tema é aplicado quando seu aplicativo é iniciado. Ele não pode ser alterado enquanto o aplicativo está em execução.

Usar estilos do sistema

Nesta seção, vamos alterar a aparência do texto (por exemplo, aumentar o tamanho da fonte).

No MainPage.xaml, encontre o TextBlock "Qual é o seu nome?". Defina a propriedade Style como uma referência à chave do recurso do sistema BaseTextBlockStyle.

<TextBlock Text="What's your name?" Style="{ThemeResource BaseTextBlockStyle}"/>

BaseTextBlockStyle é a chave de um recurso definido no ResourceDictionary em \Program Files (x86)\Windows Kits\10\DesignTime\CommonConfiguration\Neutral\UAP\<version>\Generic\generic.xaml. Aqui estão os valores de propriedade definidos por esse estilo.

<Style x:Key="BaseTextBlockStyle" TargetType="TextBlock">
    <Setter Property="FontFamily" Value="XamlAutoFontFamily" />
    <Setter Property="FontWeight" Value="SemiBold" />
    <Setter Property="FontSize" Value="14" />
    <Setter Property="TextTrimming" Value="None" />
    <Setter Property="TextWrapping" Value="Wrap" />
    <Setter Property="LineStackingStrategy" Value="MaxHeight" />
    <Setter Property="TextLineBounds" Value="Full" />
</Style>

Além disso, em MainPage.xaml, localize o TextBlock chamado greetingOutput. Defina o Style dele como BaseTextBlockStyle também. Se você compilar e executar o aplicativo agora, verá que a aparência dos dois blocos de texto foi alterada (por exemplo, o tamanho da fonte agora é maior).

Etapa 4. Adaptar a interface do usuário a diferentes tamanhos de janela

Agora, vamos fazer a interface do usuário se adaptar dinamicamente a um tamanho de janela variável e ter uma boa aparência em dispositivos com pequenas exibições. Para fazer isso, você adicionará uma seção VisualStateManager a MainPage.xaml. Você definirá estados visuais diferentes para diferentes tamanhos de janela e, em seguida, definirá as propriedades a serem aplicadas a cada um desses estados visuais.

Ajustar o layout da interface do usuário

Adicione este bloco de XAML como o primeiro elemento filho do elemento StackPanel raiz.

<StackPanel ...>
    <VisualStateManager.VisualStateGroups>
        <VisualStateGroup>
            <VisualState x:Name="wideState">
                <VisualState.StateTriggers>
                    <AdaptiveTrigger MinWindowWidth="641" />
                </VisualState.StateTriggers>
            </VisualState>
            <VisualState x:Name="narrowState">
                <VisualState.StateTriggers>
                    <AdaptiveTrigger MinWindowWidth="0" />
                </VisualState.StateTriggers>
                <VisualState.Setters>
                    <Setter Target="contentPanel.Margin" Value="20,30,0,0"/>
                    <Setter Target="inputPanel.Orientation" Value="Vertical"/>
                    <Setter Target="inputButton.Margin" Value="0,4,0,0"/>
                </VisualState.Setters>
            </VisualState>
        </VisualStateGroup>
    </VisualStateManager.VisualStateGroups>
    ...
</StackPanel>

Compile e execute o aplicativo. Observe que a interface do usuário terá a mesma aparência de antes, a menos que a janela seja redimensionada para ser mais estreita do que 641 DIPs (pixels independentes de dispositivo). Neste ponto, o estado visual narrowState é aplicado e, junto com ele, todos os definidores de propriedade desse estado.

O VisualState denominado wideState tem um AdaptiveTrigger com a propriedade MinWindowWidth definida como 641. Isso significa que o estado deverá ser aplicado somente quando a largura da janela não for menor que o mínimo de 641 DIPs. Se você não definir objetos Setter para esse estado, ele usará as propriedades de layout definidas no XAML para o conteúdo da página.

O segundo VisualState, narrowState, tem um AdaptiveTrigger com a propriedade MinWindowWidth definida como 0. Esse estado é aplicado quando a largura da janela for maior que 0, mas menor que 641 DIPs. Em exatamente 641 DIPs, wideState está em vigor. Em narrowState, você define objetos Setter para alterar as propriedades de layout de controles na interface do usuário.

  • Reduza a margem esquerda do elemento contentPanel de 120 para 20.
  • Altere a Orientação do elemento inputPanel de Horizontal para Vertical.
  • Adicione uma margem superior de 4 DIPs ao elemento inputButton.

Resumo

Esse passo a passo mostrou como adicionar conteúdo a um aplicativo universal do Windows, como adicionar interatividade e como alterar a aparência da interface do usuário.