Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
Important
Para conceitos e termos essenciais que apoiam a sua compreensão de como consumir e criar classes de runtime com C++/WinRT, veja Consume APIs with C++/WinRT e Author APIs with C++/WinRT.
Uma das funcionalidades mais poderosas do SDK de Aplicações Windows é a flexibilidade que a pilha de interface de utilizador (UI) oferece para criar controlos personalizados com base no tipo XAML Control. A framework de interface XAML fornece funcionalidades como propriedades de dependência personalizadas e propriedades associadas, e modelos de controlo, o que facilita a criação de controlos ricos em funcionalidades e personalizáveis. Este tópico guia-o pelos passos para criar um controlo personalizado (com templates) com C++/WinRT.
Criar um aplicativo em branco (BgLabelControlApp)
Comece criando um novo projeto no Microsoft Visual Studio. Crie uma Aplicação Em Branco, Empacotada (WinUI 3 no Ambiente de Trabalho) para um projeto C++, defina o nome para BgLabelControlApp e (para que a sua estrutura de pastas corresponda ao guia) certifique-se de que Colocar a solução e o projeto no mesmo diretório estão desmarcados. Utilize a versão mais recente do SDK do Windows disponível ao público (ou seja, não uma versão de pré-visualização).
Numa secção posterior deste tópico, serás orientado a construir o teu projeto (mas não o construas até lá).
Note
Para informações sobre como configurar o Visual Studio para desenvolvimento em C++/WinRT — incluindo a instalação e utilização da Extensão Visual Studio (VSIX) em C++/WinRT e do pacote NuGet (que juntos fornecem suporte para modelos de projeto e compilação) — consulte suporte ao Visual Studio para C++/WinRT.
Vamos criar uma nova classe para representar um controlo personalizado (com template). Estamos a definir e a consumir a classe dentro da mesma unidade de compilação. Mas queremos conseguir instanciar esta classe a partir da marcação XAML, e por isso vai ser uma classe em tempo de execução. E vamos usar C++/WinRT tanto para o desenvolver como para o consumir.
O primeiro passo na criação de uma nova classe de runtime é adicionar um novo item Midl File (.idl) ao projeto. Dê-lhe o nome de BgLabelControl.idl. Apague o conteúdo padrão de BgLabelControl.idl, e cole esta declaração de classe em tempo de execução.
// 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 propriedade de dependência (DP). Há duas peças para cada DP. Primeiro, declara uma propriedade estática de apenas leitura do tipo DependencyProperty. Tem o nome do seu DP seguido de Property. Você usará essa propriedade estática em sua implementação. Em segundo lugar, declara-se uma propriedade de instância de leitura e escrita com o tipo e o nome do seu DP. Se quiser criar uma propriedade anexada (em vez de uma DP), consulte os exemplos de código em Propriedades Personalizadas anexadas.
Note
Se quiseres um DP com um tipo de ponto flutuante, então faz isso double (Double em MIDL 3.0). Declarar e implementar um DP de tipo float (Single em MIDL) e, em seguida, definir um valor para esse DP na marcação XAML origina o erro Não foi possível criar um 'Windows.Foundation.Single' a partir do texto '<NUMBER>'.
Salve o arquivo. O projeto ainda não vai ser concluído, mas construir agora é útil porque gera os ficheiros de código-fonte onde vais implementar a classe de runtime BgLabelControl . Por isso, avance e constrói agora (os erros de compilação que podes esperar nesta fase têm a ver com um "símbolo externo não resolvido").
Durante o processo de compilação, a midl.exe ferramenta é executada para criar um ficheiro de metadados do Windows Runtime (\BgLabelControlApp\Debug\BgLabelControlApp\Unmerged\BgLabelControl.winmd) que descreve a classe de tempo de execução. Depois, executa-se a ferramenta cppwinrt.exe para gerar ficheiros de código-fonte que ajudem a criar e utilizar a sua classe de runtime. Estes ficheiros incluem stubs para te ajudar a começar a implementar a classe de runtime BgLabelControl que declaraste no teu IDL. Esses stubs são \BgLabelControlApp\BgLabelControlApp\Generated Files\sources\BgLabelControl.h e BgLabelControl.cpp.
Copie os ficheiros stub BgLabelControl.h e BgLabelControl.cpp de \BgLabelControlApp\BgLabelControlApp\Generated Files\sources\ para a pasta do projeto, que é \BgLabelControlApp\BgLabelControlApp\. No Explorador de Soluções, certifique-se de que Mostrar Todos os Ficheiros está ativado. Clique com o botão direito nos ficheiros stub que copiou e clique em Incluir em Project.
Verá static_assert no topo de BgLabelControl.h e BgLabelControl.cpp, que terá de eliminar. Agora o projeto vai crescer.
Implementar a classe de controlo personalizada BgLabelControl
Agora, vamos abrir \BgLabelControlApp\BgLabelControlApp\BgLabelControl.h e BgLabelControl.cpp implementar a nossa classe de runtime. Em BgLabelControl.h, altere o construtor para definir a chave de estilo padrão, implemente Label e LabelProperty, adicione um tratador de eventos estático chamado OnLabelChanged para processar alterações ao valor da propriedade de dependência e adicione um membro privado para armazenar o campo de apoio para LabelProperty.
Depois de adicionar esses, o seu BgLabelControl.h fica assim. Pode copiar e colar esta 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 assim. Pode copiar e colar esta 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 tutorial, não vamos utilizar OnLabelChanged. Mas está lá para que possas ver como registar uma propriedade de dependência com uma função de chamada de retorno para alteração da propriedade. A implementação do OnLabelChanged também mostra como obter um tipo projetado derivado a partir de um tipo projetado base (neste caso, o tipo projetado base é DependencyObject). E mostra como então 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 runtime).
Note
Se ainda não instalaste o SDK Windows versão 10.0.17763.0 (Windows 10, versão 1809), ou posterior, então tens de chamar winrt::from_abi no handler de eventos alterado da propriedade de dependência acima, em vez de winrt::get_self.
Desenhe o estilo padrão para o BgLabelControl
Em seu construtor, BgLabelControl define uma chave de estilo padrão para si mesmo. Mas o que é um estilo padrão? Um controlo personalizado (baseado em modelo) tem de ter um estilo predefinido — que contenha um modelo de controlo predefinido — que possa usar para se apresentar, caso o utilizador do controlo não defina um estilo e/ou um modelo. Nesta seção, adicionaremos um arquivo de marcação ao projeto contendo nosso estilo padrão.
Certifique-se de que Mostrar Todos os Ficheiros ainda está ativado (em Explorador 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 nomeie-o "Generic.xaml". Os nomes das pastas e ficheiros têm de ser assim para que o framework XAML encontre o estilo padrão para um controlo personalizado. Apague o conteúdo padrão de Generic.xaml, e cole a 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 modelo consiste num quadrado (cujo fundo está ligado à propriedade Background que todas as instâncias do tipo XAML Control possuem) e num elemento de texto (cujo texto está ligado à propriedade de dependência BgLabelControl::Label ).
Adicione uma instância do BgLabelControl à página principal da interface
Abra o MainPage.xaml, que contém a marcação XAML para a nossa página principal da interface de utilizador. Imediatamente após o elemento Button (dentro do 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 da compilação de marcação XAML e de código imperativo) reconheça o tipo de controlo personalizado BgLabelControl. Se você quiser usar BgLabelControl de outra página XAML, adicione essa mesma diretiva include ao arquivo de cabeçalho dessa página também. Ou, alternativamente, basta colocar uma única diretiva include em seu 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 de fundo e ao rótulo da instância do BgLabelControl na marcação.
Este tutorial mostrou um exemplo simples de um controlo personalizado (com modelo) em C++/WinRT. Podes criar os teus próprios controlos personalizados arbitrariamente ricos e completos. Por exemplo, um controlo personalizado pode assumir a forma de algo tão complicado como uma grelha de dados editável, um leitor de vídeo ou um visualizador de geometria 3D.
Implementação de métodos substituíveis, como MeasureOverride e OnApplyTemplate
Consulte a secção em Chamar e substituir o seu tipo base com C++/WinRT.
APIs importantes
Tópicos relacionados
Windows developer