Criar controles XAML com C#

Este artigo orienta você na criação de um controle XAML com modelo para WinUI 3 com C#. Controles com modelo herdam de Microsoft.UI.XAML.Controls.Control e têm estrutura visual e comportamento visual que podem ser personalizados usando modelos de controle XAML.

Para criar componentes WinUI 3 autônomos em C# para consumo tanto de aplicativos C# quanto do C++/WinRT, confira o artigo Passo a passo: criar um componente de C# com controles WinUI 3 e consumi-lo em um aplicativo do SDK de Aplicativo Windows do C++.

Pré-requisitos

  1. Para configurar seu ambiente de desenvolvimento, confira Instalar ferramentas para o SDK do Aplicativo Windows.
  2. Siga as instruções de como Criar seu primeiro projeto da WinUI 3.

Criar um aplicativo em branco (BgLabelControlApp)

Comece criando um novo projeto no Microsoft Visual Studio. Na caixa de diálogo Criar um projeto, selecione o modelo de projeto Aplicativo em Branco, empacotado (WinUI 3 na Área de Trabalho), verificando se selecionou a versão de linguagem do C#. Defina o nome do projeto como "BgLabelControlApp" para que os nomes de arquivo sejam alinhados com o código nos exemplos abaixo.

Modelo de Projeto de Aplicativo em Branco

Adicionar um controle com modelo ao aplicativo

Para adicionar um controle com modelo, clique no menu Projeto na barra de ferramentas ou clique com o botão direito do mouse em seu projeto no Gerenciador de Soluções e selecione Adicionar novo item. Em Visual C#->WinUI, selecione o modelo Controle Personalizado (WinUI 3). Chame o novo controle de "BgLabelControl" e clique em Adicionar.

Atualizar o arquivo C# de controle personalizado

No arquivo C#, BgLabelControl.cs, observe que o construtor define a propriedade DefaultStyleKey do nosso controle. Essa chave identifica o modelo padrão que será usado se o consumidor do controle não especificar explicitamente um modelo. O valor da chave é o tipo do controle. Veremos essa chave em uso posteriormente, quando implementarmos um arquivo de modelo genérico.

public BgLabelControl()
{
    this.DefaultStyleKey = typeof(BgLabelControl);
}

O controle com modelo terá um rótulo de texto que pode ser definido programaticamente no código, em XAML, ou por meio da vinculação de dados. Para que o sistema mantenha o texto do rótulo do controle atualizado, ele precisa ser implementado como uma DependencyPropety. Para fazer isso, primeiro declaramos uma propriedade de cadeia de caracteres e a chamamos de Rótulo. Em vez de usar uma variável de suporte, obtemos e definimos o valor da propriedade de dependência chamando os métodos GetValue e SetValue. Esses métodos são fornecidos pelo DependencyObject, que é herdado por Microsoft.UI.Xaml.Controls.Control.

public string Label
{
    get => (string)GetValue(LabelProperty);
    set => SetValue(LabelProperty, value);
}

Em seguida, declare a propriedade de dependência e registre-a no sistema chamando o método DependencyProperty. Register. Esse método especifica o nome e o tipo da propriedade Rótulo, o tipo do proprietário dela, a classe BgLabelControl e o valor padrão da propriedade.

DependencyProperty LabelProperty = DependencyProperty.Register(
    nameof(Label), 
    typeof(string),
    typeof(BgLabelControl), 
    new PropertyMetadata(default(string), new PropertyChangedCallback(OnLabelChanged)));

Essas duas etapas são obrigatórias para implementar uma propriedade de dependência. Contudo, para este exemplo, adicionaremos um manipulador opcional para o evento OnLabelChanged. Esse evento é gerado pelo sistema sempre que o valor da propriedade é atualizado. Nesse caso, verificamos se o novo texto do rótulo é uma cadeia de caracteres vazia ou não e atualizamos uma variável de classe com base nessa verificação.

public bool HasLabelValue { get; set; }

private static void OnLabelChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    BgLabelControl labelControl = d as BgLabelControl; //null checks omitted
    String s = e.NewValue as String; //null checks omitted
    if (s == String.Empty)
    {
        labelControl.HasLabelValue = false;
    }
    else
    {
        labelControl.HasLabelValue = true;
    }
}

Para saber mais sobre como as propriedades de dependência funcionam, confira Visão geral das propriedades de dependência.

Definir o estilo padrão para BgLabelControl

Um controle com modelo deve fornecer um modelo de estilo padrão que será usado se o usuário do controle não definir explicitamente um estilo. Nesta etapa, modificaremos o arquivo de modelo genérico para o controle.

O arquivo de modelo genérico é gerado quando você adiciona o Controle Personalizado (WinUI) ao aplicativo. O nome do arquivo é "Generic.xaml" e ele é gerado na pasta Temas no gerenciador de soluções. Os nomes de pasta e arquivo são necessários para que a estrutura XAML localize o estilo padrão para um controle com modelo. Exclua o conteúdo padrão do 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>

Neste exemplo, você pode ver que o atributo TargetType do elemento Estilo é definido como o tipo BgLabelControl dentro do namespace BgLabelControlApp. Esse tipo é o mesmo valor que especificamos acima para a propriedade DefaultStyleKey, no construtor do controle que identifica ele como o estilo padrão do controle.

A propriedade Texto do TextBlock no modelo do controle está associada à propriedade de dependência do Rótulo do controle. A propriedade é associada usando a extensão de marcação TemplateBinding. Este exemplo também associa a tela de fundo da Grade à propriedade de dependência da Tela de fundo, que é herdada da classe Controle.

Adicionar uma instância de BgLabelControl à página da interface do usuário principal

Abra MainWindow.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!"/>

Compile e execute o aplicativo e você verá o controle com modelo, com a cor da tela de fundo e o rótulo especificados.

Resultado do controle com modelo

Confira também