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.
Com o Windows Presentation Foundation (WPF), você pode personalizar a estrutura visual e o comportamento de um controle existente com seu próprio modelo reutilizável. Os modelos podem ser aplicados globalmente ao seu aplicativo, janelas e páginas ou diretamente aos controles. A maioria dos cenários que exigem que você crie um novo controle pode ser abordada criando um novo modelo para um controle existente.
Neste artigo, você explorará a criação de um novo ControlTemplate para o Button controle.
Quando criar um ControlTemplate
Os controles têm muitas propriedades, como Background, Foregrounde FontFamily. Essas propriedades controlam diferentes aspectos da aparência do controle, mas as alterações que você pode fazer definindo essas propriedades são limitadas. Por exemplo, você pode definir a Foreground propriedade como azul e FontStyle itálico em um CheckBox. Quando você quiser personalizar a aparência do controle além do que é possível com as outras propriedades, crie um ControlTemplate.
Na maioria das interfaces do usuário, um botão tem a mesma aparência geral: um retângulo com algum texto. Se você quiser criar um botão arredondado, poderá criar um novo controle que herda do botão ou recrie a funcionalidade do botão. Além disso, o novo controle de usuário forneceria o visual circular.
Você pode evitar a criação de novos controles personalizando o layout visual de um controle existente. Com um botão arredondado, você cria um ControlTemplate com o layout visual desejado.
Por outro lado, se você precisar de um controle com novas funcionalidades, propriedades diferentes e novas configurações, você criará um novo UserControl.
Pré-requisitos
Crie um novo aplicativo WPF e, em MainWindow.xaml (ou outra janela de sua escolha), defina as seguintes propriedades no <elemento Window> :
Propriedade | Valor |
---|---|
Title | Template Intro Sample |
SizeToContent | WidthAndHeight |
MinWidth | 250 |
Defina o conteúdo do <elemento Window> para o seguinte XAML:
<StackPanel Margin="10">
<Label>Unstyled Button</Label>
<Button>Button 1</Button>
<Label>Rounded Button</Label>
<Button>Button 2</Button>
</StackPanel>
No final, o arquivo MainWindow.xaml deve ser semelhante ao seguinte:
<Window x:Class="IntroToStylingAndTemplating.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:IntroToStylingAndTemplating"
mc:Ignorable="d"
Title="Template Intro Sample" SizeToContent="WidthAndHeight" MinWidth="250">
<StackPanel Margin="10">
<Label>Unstyled Button</Label>
<Button>Button 1</Button>
<Label>Rounded Button</Label>
<Button>Button 2</Button>
</StackPanel>
</Window>
Se você executar o aplicativo, ele será semelhante ao seguinte:
Criar um ControlTemplate
A maneira mais comum de declarar um ControlTemplate é como um recurso na Resources
seção em um arquivo XAML. Como os modelos são recursos, eles obedecem às mesmas regras de escopo que se aplicam a todos os recursos. Simplificando, onde você declara um modelo afeta onde o modelo pode ser aplicado. Por exemplo, se você declarar o modelo no elemento raiz do arquivo XAML de definição de aplicativo, o modelo poderá ser usado em qualquer lugar do aplicativo. Se você definir o modelo em uma janela, somente os controles nessa janela poderão usar o modelo.
Para começar, adicione um Window.Resources
elemento ao arquivo MainWindow.xaml :
<Window x:Class="IntroToStylingAndTemplating.Window2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:IntroToStylingAndTemplating"
mc:Ignorable="d"
Title="Template Intro Sample" SizeToContent="WidthAndHeight" MinWidth="250">
<Window.Resources>
</Window.Resources>
<StackPanel Margin="10">
<Label>Unstyled Button</Label>
<Button>Button 1</Button>
<Label>Rounded Button</Label>
<Button>Button 2</Button>
</StackPanel>
</Window>
Crie um novo <ControlTemplate> com o seguinte conjunto de propriedades:
Propriedade | Valor |
---|---|
x:Key | roundbutton |
TargetType | Button |
Este modelo de controle será simples:
- um elemento raiz para o controle, um Grid
- um Ellipse para desenhar a aparência arredondada do botão
- a ContentPresenter para exibir o conteúdo do botão especificado pelo usuário
<ControlTemplate x:Key="roundbutton" TargetType="Button">
<Grid>
<Ellipse Fill="{TemplateBinding Background}" Stroke="{TemplateBinding Foreground}" />
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
</Grid>
</ControlTemplate>
TemplateBinding
Ao criar um novo ControlTemplate, talvez você ainda queira usar as propriedades públicas para alterar a aparência do controle. A extensão de marcação TemplateBinding associa uma propriedade de um elemento que está em ControlTemplate a uma propriedade pública definida pelo controle. Ao usar um TemplateBinding, você permite que as propriedades no controle atuem como parâmetros para o modelo. Ou seja, quando uma propriedade em um controle é definida, esse valor é passado para o elemento que tem o TemplateBinding nele.
Elipse
Observe que as propriedades Fill e Stroke do elemento <Elipse> estão associadas às propriedades Foreground e Background do controle.
Apresentador de Conteúdo
Um <elemento ContentPresenter> também é adicionado ao modelo. Como esse modelo foi projetado para um botão, leve em consideração que o botão herda de ContentControl. O botão apresenta o conteúdo do elemento. Você pode definir qualquer coisa dentro do botão, como texto sem formatação ou até mesmo outro controle. Ambos os seguintes botões são válidos:
<Button>My Text</Button>
<!-- and -->
<Button>
<CheckBox>Checkbox in a button</CheckBox>
</Button>
Em ambos os exemplos anteriores, o texto e a caixa de seleção são definidos como a propriedade Button.Content . O que for definido como o conteúdo pode ser apresentado por meio de um <ContentPresenter>, que é o que o modelo faz.
Se ControlTemplate for aplicado a um tipo ContentControl, como Button
, um ContentPresenter será pesquisado na árvore de elementos. Se o ContentPresenter
for encontrado, o modelo associará automaticamente a propriedade do controle Content ao ContentPresenter
.
Usar o modelo
Localize os botões que foram declarados no início deste artigo.
<StackPanel Margin="10">
<Label>Unstyled Button</Label>
<Button>Button 1</Button>
<Label>Rounded Button</Label>
<Button>Button 2</Button>
</StackPanel>
Defina a propriedade do Template segundo botão para o recurso roundbutton
.
<StackPanel Margin="10">
<Label>Unstyled Button</Label>
<Button>Button 1</Button>
<Label>Rounded Button</Label>
<Button Template="{StaticResource roundbutton}">Button 2</Button>
</StackPanel>
Se você executar o projeto e examinar o resultado, verá que o botão tem uma tela de fundo arredondada.
Você deve ter notado que o botão não é um círculo, mas está distorcido. Devido à maneira como o <elemento Elipse> funciona, ele sempre se expande para preencher o espaço disponível. Torne o círculo uniforme alterando as propriedades width e height do botão para o mesmo valor.
<StackPanel Margin="10">
<Label>Unstyled Button</Label>
<Button>Button 1</Button>
<Label>Rounded Button</Label>
<Button Template="{StaticResource roundbutton}" Width="65" Height="65">Button 2</Button>
</StackPanel>
Adicionar um gatilho
Mesmo que um botão com um modelo aplicado pareça diferente, ele se comporta da mesma forma que qualquer outro botão. Se você pressionar o botão, o Click evento será acionado. No entanto, talvez você tenha notado que, quando você move o mouse sobre o botão, os visuais do botão não são alterados. Essas interações visuais são definidas pelo modelo.
Com os sistemas dinâmicos de eventos e propriedades fornecidos pelo WPF, você pode observar uma propriedade específica para um valor e, em seguida, reestilizar o modelo quando apropriado. Neste exemplo, você observará a propriedade do botão IsMouseOver. Quando o mouse estiver sobre o controle, estilo a <elipse> com uma nova cor. Esse tipo de gatilho é conhecido como PropertyTrigger.
Para que isso funcione, você precisará adicionar um nome à <Elipse> que você possa referenciar. Dê a ele o nome de backgroundElement.
<Ellipse x:Name="backgroundElement" Fill="{TemplateBinding Background}" Stroke="{TemplateBinding Foreground}" />
Em seguida, adicione uma nova Trigger à coleção ControlTemplate.Triggers . O gatilho observará o evento IsMouseOver
para o valor true
.
<ControlTemplate x:Key="roundbutton" TargetType="Button">
<Grid>
<Ellipse x:Name="backgroundElement" Fill="{TemplateBinding Background}" Stroke="{TemplateBinding Foreground}" />
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
Em seguida, adicione um <Setter> ao <Trigger> que altera a propriedade Fill da <elipse> para uma nova cor.
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Fill" TargetName="backgroundElement" Value="AliceBlue"/>
</Trigger>
Execute o projeto . Observe que quando você move o mouse sobre o botão, a cor da <elipse> é alterada.
Usar um VisualState
Os estados visuais são definidos e disparados por um controle. Por exemplo, quando o mouse é movido sobre o controle, o estado CommonStates.MouseOver
é ativado. Você pode animar mudanças nas propriedades com base no estado atual do controle. Na seção anterior, um <PropertyTrigger> foi usado para alterar o fundo do botão para AliceBlue
quando a propriedade IsMouseOver
era true
. Em vez disso, crie um estado visual que anime a alteração dessa cor, assegurando uma transição suave. Para obter mais informações sobre o VisualStates, consulte Estilos e modelos no WPF.
Para converter o <PropertyTrigger> em um estado visual animado, primeiro, remova o <elemento ControlTemplate.Triggers> do seu modelo.
<ControlTemplate x:Key="roundbutton" TargetType="Button">
<Grid>
<Ellipse x:Name="backgroundElement" Fill="{TemplateBinding Background}" Stroke="{TemplateBinding Foreground}" />
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
</Grid>
</ControlTemplate>
Em seguida, na <Grid> raiz do modelo de controle, adicione o <elemento VisualStateManager.VisualStateGroups> com um <VisualStateGroup> para CommonStates
. Definir dois estados Normal
e MouseOver
.
<ControlTemplate x:Key="roundbutton" TargetType="Button">
<Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup Name="CommonStates">
<VisualState Name="Normal">
</VisualState>
<VisualState Name="MouseOver">
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Ellipse x:Name="backgroundElement" Fill="{TemplateBinding Background}" Stroke="{TemplateBinding Foreground}" />
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
</Grid>
</ControlTemplate>
Todas as animações definidas em um <VisualState> são aplicadas quando esse estado é disparado. Crie animações para cada estado. As animações são colocadas dentro de um <elemento Storyboard> . Para obter mais informações sobre roteiros gráficos, consulte Visão geral de roteiros gráficos.
Normal
Esse estado anima o preenchimento da elipse, restaurando-o para a cor do controle
Background
.<Storyboard> <ColorAnimation Storyboard.TargetName="backgroundElement" Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)" To="{TemplateBinding Background}" Duration="0:0:0.3"/> </Storyboard>
Passe o Mouse
Esse estado anima a cor da elipse
Background
para uma nova cor:Yellow
.<Storyboard> <ColorAnimation Storyboard.TargetName="backgroundElement" Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)" To="Yellow" Duration="0:0:0.3"/> </Storyboard>
O <ControlTemplate> agora deve ser semelhante ao seguinte.
<ControlTemplate x:Key="roundbutton" TargetType="Button">
<Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup Name="CommonStates">
<VisualState Name="Normal">
<Storyboard>
<ColorAnimation Storyboard.TargetName="backgroundElement"
Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)"
To="{TemplateBinding Background}"
Duration="0:0:0.3"/>
</Storyboard>
</VisualState>
<VisualState Name="MouseOver">
<Storyboard>
<ColorAnimation Storyboard.TargetName="backgroundElement"
Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)"
To="Yellow"
Duration="0:0:0.3"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Ellipse Name="backgroundElement" Fill="{TemplateBinding Background}" Stroke="{TemplateBinding Foreground}" />
<ContentPresenter x:Name="contentPresenter" HorizontalAlignment="Center" VerticalAlignment="Center" />
</Grid>
</ControlTemplate>
Execute o projeto . Observe que quando você move o mouse sobre o botão, a <cor da elipse> é animada.
Próximas etapas
.NET Desktop feedback