Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Important
Para obter conceitos e termos essenciais que dão suporte à compreensão de como consumir e criar classes de runtime com C++/WinRT, consulte Consumir APIs com APIs C++/WinRT e Criar com C++/WinRT.
Um dos recursos mais poderosos do SDK do Aplicativo Windows é a flexibilidade que a camada de interface do usuário (IU) oferece para a criação de controles personalizados com base no tipo XAML Control. A estrutura de interface do usuário XAML fornece recursos como propriedades de dependência personalizadas e propriedades anexadas e modelos de controle, o que facilita a criação de controles personalizáveis e avançados em recursos. Este tópico orienta você pelas etapas de criação de um controle personalizado (modelo) com C++/WinRT.
Criar um aplicativo em branco (BgLabelControlApp)
Comece criando um novo projeto no Microsoft Visual Studio. Crie um Aplicativo em branco, empacotado (WinUI 3 na área de trabalho) para o projeto C++, defina seu nome como BgLabelControlAppe (para que sua estrutura de pastas corresponda ao passo a passo) certifique-se de que a opção Colocar solução e projeto no mesmo diretório esteja desmarcada. Direcione a versão mais recente disponível (ou seja, não 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 crie até lá).
Note
Para obter informações sobre como configurar Visual Studio para o desenvolvimento do C++/WinRT, incluindo a instalação e o uso da VSIX (Extensão de Visual Studio) do C++/WinRT e do pacote NuGet (que, juntos, fornecem modelo de projeto e suporte de build)— consulte Visual Studio suporte para C++/WinRT.
Vamos criar uma nova classe para representar um controle personalizado com modelo. Estamos criando e consumindo a classe na mesma unidade de compilação. Entretanto, queremos poder instanciar essa classe pela marcação do XAML e, por isso, ela será uma classe de runtime. E vamos usar C++/WinRT tanto para desenvolvê-lo quanto para consumi-lo.
A primeira etapa na criação de uma nova classe de runtime é adicionar um novo item midl file (.idl) ao projeto. Nomeie como BgLabelControl.idl. Exclua o conteúdo padrão de BgLabelControl.idl e cole esta declaração de classe de runtime.
// BgLabelControl.idl
namespace BgLabelControlApp
{
runtimeclass BgLabelControl : Microsoft.UI.Xaml.Controls.Control
{
BgLabelControl();
static Microsoft.UI.Xaml.DependencyProperty LabelProperty{ get; };
String Label;
}
}
A listagem acima mostra o padrão que você segue ao declarar uma DP (propriedade de dependência). Há duas partes para cada DP. Primeiro, você declara uma propriedade estática de somente leitura do tipo DependencyProperty. Ela tem o nome da sua DP e Property. Você usará essa propriedade estática em sua implementação. Em seguida, declare uma propriedade de instância de leitura/gravação com o tipo e o nome da sua DP. Se você quiser criar uma propriedade anexada (em vez de um DP), consulte os exemplos de código em propriedades anexadas personalizadas.
Note
Se você quiser um DP com um tipo de ponto flutuante, faça isso double (Double em MIDL 3.0). Declarar e implementar uma DP do tipo float (Single em MIDL) e, em seguida, definir um valor para essa DP na marcação XAML resulta no erro Falha ao criar 'Windows.Foundation.Single' do texto '<NUMBER>'.
Salve o arquivo. No momento, o projeto não será compilado até o fim, mas compilá-lo agora ainda é útil porque isso gera os arquivos de código-fonte nos quais você implementará a classe de tempo de execução BgLabelControl. Portanto, vá em frente e crie agora (os erros de build que você pode esperar ver neste estágio têm a ver com um "símbolo externo não resolvido").
Durante o processo de build, a midl.exe ferramenta é executada para criar um arquivo de metadados Windows Runtime (\BgLabelControlApp\Debug\BgLabelControlApp\Unmerged\BgLabelControl.winmd) descrevendo a classe de runtime. Em seguida, a cppwinrt.exe ferramenta é executada para gerar arquivos de código-fonte para dar suporte a você na criação e no consumo da classe de runtime. Esses arquivos incluem stubs para que você comece a implementar a classe de runtime BgLabelControl que você declarou em sua IDL. Esses stubs são \BgLabelControlApp\BgLabelControlApp\Generated Files\sources\BgLabelControl.h e BgLabelControl.cpp.
Copie os arquivos stub BgLabelControl.h e BgLabelControl.cpp de \BgLabelControlApp\BgLabelControlApp\Generated Files\sources\ para a pasta do projeto, que é \BgLabelControlApp\BgLabelControlApp\. Em Gerenciador de Soluções, verifique se a opção Mostrar Todos os Arquivos está ativada. Clique com o botão direito do mouse nos arquivos stub copiados e clique em Include In Project.
Você verá um static_assert na parte superior de BgLabelControl.h e BgLabelControl.cpp, que você precisará remover. Agora o projeto será criado.
Implementar a classe de controle personalizado BgLabelControl
Agora, vamos abrir \BgLabelControlApp\BgLabelControlApp\BgLabelControl.h e BgLabelControl.cpp implementar nossa classe de runtime. In BgLabelControl.h, altere o construtor para definir a chave de estilo padrão, implementar Label e LabelProperty, adicionar um manipulador de eventos estático chamado OnLabelChanged para processar alterações no valor da propriedade de dependência e adicionar um membro privado para armazenar o campo de backup para LabelProperty.
Depois de adicioná-los, seu BgLabelControl.h fica assim. Você pode copiar e colar essa listagem de código para substituir o conteúdo de BgLabelControl.h.
// BgLabelControl.h
#pragma once
#include "BgLabelControl.g.h"
namespace winrt::BgLabelControlApp::implementation
{
struct BgLabelControl : BgLabelControlT<BgLabelControl>
{
BgLabelControl() { DefaultStyleKey(winrt::box_value(L"BgLabelControlApp.BgLabelControl")); }
winrt::hstring Label()
{
return winrt::unbox_value<winrt::hstring>(GetValue(m_labelProperty));
}
void Label(winrt::hstring const& value)
{
SetValue(m_labelProperty, winrt::box_value(value));
}
static Microsoft::UI::Xaml::DependencyProperty LabelProperty() { return m_labelProperty; }
static void OnLabelChanged(Microsoft::UI::Xaml::DependencyObject const&, Microsoft::UI::Xaml::DependencyPropertyChangedEventArgs const&);
private:
static Microsoft::UI::Xaml::DependencyProperty m_labelProperty;
};
}
namespace winrt::BgLabelControlApp::factory_implementation
{
struct BgLabelControl : BgLabelControlT<BgLabelControl, implementation::BgLabelControl>
{
};
}
Em BgLabelControl.cpp, defina os membros estáticos como este. Você pode copiar e colar essa listagem de código para substituir o conteúdo de BgLabelControl.cpp.
// BgLabelControl.cpp
#include "pch.h"
#include "BgLabelControl.h"
#include "BgLabelControl.g.cpp"
namespace winrt::BgLabelControlApp::implementation
{
Microsoft::UI::Xaml::DependencyProperty BgLabelControl::m_labelProperty =
Microsoft::UI::Xaml::DependencyProperty::Register(
L"Label",
winrt::xaml_typename<winrt::hstring>(),
winrt::xaml_typename<BgLabelControlApp::BgLabelControl>(),
Microsoft::UI::Xaml::PropertyMetadata{ winrt::box_value(L"default label"), Microsoft::UI::Xaml::PropertyChangedCallback{ &BgLabelControl::OnLabelChanged } }
);
void BgLabelControl::OnLabelChanged(Microsoft::UI::Xaml::DependencyObject const& d, Microsoft::UI::Xaml::DependencyPropertyChangedEventArgs const& /* e */)
{
if (BgLabelControlApp::BgLabelControl theControl{ d.try_as<BgLabelControlApp::BgLabelControl>() })
{
// Call members of the projected type via theControl.
BgLabelControlApp::implementation::BgLabelControl* ptr{ winrt::get_self<BgLabelControlApp::implementation::BgLabelControl>(theControl) };
// Call members of the implementation type via ptr.
}
}
}
Neste passo a passo, não usaremos OnLabelChanged. Entretanto, ele continua lá para que você possa ver como registrar uma propriedade de dependência com um retorno de chamada de propriedade alterada. A implementação de OnLabelChanged também mostra como obter um tipo projetado derivado de um tipo projetado de base (o tipo projetado base é DependencyObject, nesse caso). E mostra como obter um ponteiro para o tipo que implementa o tipo projetado. Essa segunda operação naturalmente só será possível no projeto que implementa o tipo projetado (ou seja, o projeto que implementa a classe de runtime).
Note
Se você ainda não instalou o SDK Windows versão 10.0.17763.0 (Windows 10, versão 1809) ou posterior, você precisará chamar winrt::from_abi no manipulador de eventos alterado da propriedade de dependência acima, em vez de winrt::get_self.
Projetar o estilo padrão para BgLabelControl
Em seu construtor, BgLabelControl define uma chave de estilo padrão para si mesmo. Mas o que é um estilo padrão? Um controle personalizado (com template) precisa ter um estilo padrão — contendo um template de controle padrão — que ele possa usar para ser renderizado caso o consumidor do controle não defina um estilo e/ou template. Nesta seção, adicionaremos um arquivo de marcação ao projeto que contém nosso estilo padrão.
Verifique se Mostrar Todos os Arquivos ainda está ativada (em Gerenciador de Soluções). No nó do projeto, crie uma nova pasta (não um filtro, mas uma pasta) e nomeie-a como "Temas". Em Themes, adicione um novo item do tipo Visual C++>XAML>XAML View e dê a ele o nome de "Generic.xaml". Os nomes de pasta e arquivo devem ser assim para que a estrutura XAML localize o estilo padrão para um controle personalizado. Exclua o conteúdo padrão de Generic.xaml e cole-o na marcação abaixo.
<!-- \Themes\Generic.xaml -->
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:BgLabelControlApp">
<Style TargetType="local:BgLabelControl" >
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:BgLabelControl">
<Grid Width="100" Height="100" Background="{TemplateBinding Background}">
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Text="{TemplateBinding Label}"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
Nesse caso, a única propriedade que o estilo padrão define é o modelo de controle. O template consiste em um quadrado (cujo plano de fundo está vinculado à propriedade Background, presente em todas as instâncias do tipo XAML Control) e em um elemento de texto (cujo texto está vinculado à propriedade de dependência BgLabelControl::Label).
Adicionar uma instância de BgLabelControl à página principal da interface do usuário
Abra MainPage.xaml, que contém a marcação XAML para a página principal da interface do usuário. Imediatamente após o elemento Button (dentro de StackPanel), adicione a seguinte marcação.
<local:BgLabelControl Background="Red" Label="Hello, World!"/>
Além disso, adicione a seguinte diretiva include a MainPage.h para que o tipo MainPage (uma combinação de compilação de markup XAML e código imperativo) reconheça o tipo de controle personalizado BgLabelControl. Se você quiser usar BgLabelControl de outra página XAML, adicione essa mesma diretiva de inclusão ao arquivo de cabeçalho para essa página também. Ou, como alternativa, basta colocar uma única diretiva de inclusão no arquivo de cabeçalho pré-compilado.
// MainPage.h
...
#include "BgLabelControl.h"
...
Agora, construa e execute o projeto. Você verá que o modelo de controle padrão está associado ao pincel do plano de fundo e ao rótulo da instância BgLabelControl na marcação.
Este passo a passo apresentou um exemplo simples de um controle personalizado com modelo no C++/WinRT. Você pode tornar seus próprios controles personalizados arbitrariamente ricos e completos. Por exemplo, um controle personalizado pode assumir a forma de algo tão complicado quanto uma grade de dados editável, um player de vídeo ou um visualizador de geometria 3D.
Como implementar funções substituíveis, como MeasureOverride e OnApplyTemplate
Consulte a seção em Chamando e substituindo seu tipo de base com C++/WinRT.
APIs importantes
Tópicos relacionados:
Windows developer