Nota
O acesso a esta página requer autorização. Podes tentar iniciar sessão ou mudar de diretório.
O acesso a esta página requer autorização. Podes tentar mudar de diretório.
O estilo e a modelagem do Windows Presentation Foundation (WPF) referem-se a um conjunto de recursos que permitem que desenvolvedores e designers criem efeitos visualmente atraentes e uma aparência consistente para seus produtos. Ao personalizar a aparência de um aplicativo, você deseja um modelo de modelagem e estilo forte que permita a manutenção e o compartilhamento da aparência dentro e entre aplicativos. O WPF fornece esse modelo.
Outra característica do modelo de estilo WPF é a separação entre apresentação e lógica. Os designers podem trabalhar na aparência de um aplicativo usando apenas XAML ao mesmo tempo em que os desenvolvedores trabalham na lógica de programação usando C# ou Visual Basic.
Esta visão geral se concentra nos aspetos de estilo e modelagem do aplicativo e não discute nenhum conceito de vinculação de dados. Para obter informações sobre vinculação de dados, consulte Visão geral da vinculação de dados.
É importante entender os recursos, que são o que permitem que estilos e modelos sejam reutilizados. Para obter mais informações sobre recursos, consulte Visão geral dos recursos XAML.
Exemplo
O código de exemplo fornecido nesta visão geral é baseado em um aplicativo de navegação de fotos simples mostrado na ilustração a seguir.
Este exemplo de foto simples usa estilização e modelagem para criar uma experiência de usuário visualmente atraente. O exemplo tem dois TextBlock elementos e um ListBox controle que está vinculado a uma lista de imagens.
Para obter o exemplo completo, consulte Introdução ao Exemplo de Estilização e Modelagem.
Estilos
Você pode pensar em Style como uma maneira conveniente de aplicar um conjunto de propriedades a vários elementos. Você pode usar um estilo em qualquer elemento que seja derivado de FrameworkElement ou FrameworkContentElement, como um Window ou um Button.
A maneira mais comum de declarar um estilo é como um recurso na seção Resources em um arquivo XAML. Como os estilos são recursos, eles obedecem às mesmas regras de escopo que se aplicam a todos os recursos. Simplificando, onde você declara um estilo afeta onde o estilo pode ser aplicado. Por exemplo, se você declarar o estilo no elemento raiz do arquivo XAML de definição de aplicativo, o estilo poderá ser usado em qualquer lugar do aplicativo.
Por exemplo, o código XAML a seguir declara dois estilos para um TextBlock, um aplicado automaticamente a todos os TextBlock elementos e outro que deve ser explicitamente referenciado.
<Window.Resources>
<!-- .... other resources .... -->
<!--A Style that affects all TextBlocks-->
<Style TargetType="TextBlock">
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="FontFamily" Value="Comic Sans MS"/>
<Setter Property="FontSize" Value="14"/>
</Style>
<!--A Style that extends the previous TextBlock Style with an x:Key of TitleText-->
<Style BasedOn="{StaticResource {x:Type TextBlock}}"
TargetType="TextBlock"
x:Key="TitleText">
<Setter Property="FontSize" Value="26"/>
<Setter Property="Foreground">
<Setter.Value>
<LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
<LinearGradientBrush.GradientStops>
<GradientStop Offset="0.0" Color="#90DDDD" />
<GradientStop Offset="1.0" Color="#5BFFFF" />
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
Aqui está um exemplo dos estilos declarados acima sendo usados.
<StackPanel>
<TextBlock Style="{StaticResource TitleText}" Name="textblock1">My Pictures</TextBlock>
<TextBlock>Check out my new pictures!</TextBlock>
</StackPanel>
Para obter mais informações, consulte Criar um estilo para um controle.
ControlTemplates
No WPF, o ControlTemplate de um controle define a aparência do controle. Você pode alterar a estrutura e a aparência de um controle definindo um novo ControlTemplate e atribuindo-o a um controle. Em muitos casos, os modelos oferecem flexibilidade suficiente para que você não precise escrever seus próprios controles personalizados.
Cada controle tem um modelo padrão atribuído à propriedade Control.Template . O modelo conecta a apresentação visual do controle com os recursos do controle. Como você define um modelo em XAML, pode alterar a aparência do controle sem escrever nenhum código. Cada modelo é projetado para um controle específico, como um Button.
Normalmente, você declara um modelo como um recurso na Resources seção de um arquivo XAML. Tal como acontece com todos os recursos, aplicam-se regras de delimitação.
Os modelos de controle são muito mais complexos do que um estilo. Isso ocorre porque o modelo de controle reescreve a aparência visual de todo o controle, enquanto um estilo simplesmente aplica alterações de propriedade ao controle existente. No entanto, como o modelo de um controle é aplicado definindo a propriedade Control.Template , você pode usar um estilo para definir ou definir um modelo.
Os designers geralmente permitem que você crie uma cópia de um modelo existente e modifique-o. Por exemplo, no designer WPF do Visual Studio, selecione um CheckBox controle e, em seguida, clique com o botão direito do mouse e selecione Editar modelo>Criar uma cópia. Este comando gera um estilo que define um modelo.
<Style x:Key="CheckBoxStyle1" TargetType="{x:Type CheckBox}">
<Setter Property="FocusVisualStyle" Value="{StaticResource FocusVisual1}"/>
<Setter Property="Background" Value="{StaticResource OptionMark.Static.Background1}"/>
<Setter Property="BorderBrush" Value="{StaticResource OptionMark.Static.Border1}"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type CheckBox}">
<Grid x:Name="templateRoot" Background="Transparent" SnapsToDevicePixels="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Border x:Name="checkBoxBorder" Background="{TemplateBinding Background}" BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="{TemplateBinding BorderBrush}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="1" VerticalAlignment="{TemplateBinding VerticalContentAlignment}">
<Grid x:Name="markGrid">
<Path x:Name="optionMark" Data="F1 M 9.97498,1.22334L 4.6983,9.09834L 4.52164,9.09834L 0,5.19331L 1.27664,3.52165L 4.255,6.08833L 8.33331,1.52588e-005L 9.97498,1.22334 Z " Fill="{StaticResource OptionMark.Static.Glyph1}" Margin="1" Opacity="0" Stretch="None"/>
<Rectangle x:Name="indeterminateMark" Fill="{StaticResource OptionMark.Static.Glyph1}" Margin="2" Opacity="0"/>
</Grid>
</Border>
<ContentPresenter x:Name="contentPresenter" Grid.Column="1" Focusable="False" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="HasContent" Value="true">
<Setter Property="FocusVisualStyle" Value="{StaticResource OptionMarkFocusVisual1}"/>
<Setter Property="Padding" Value="4,-1,0,0"/>
... content removed to save space ...
Editar uma cópia de um modelo é uma ótima maneira de aprender como os modelos funcionam. Em vez de criar um novo modelo em branco, é mais fácil editar uma cópia e alterar alguns aspetos da apresentação visual.
Para obter um exemplo, consulte Criar um modelo para um controle.
TemplateBinding
Você pode ter notado que o recurso de modelo definido na seção anterior usa a extensão de marcação TemplateBinding. A TemplateBinding é uma forma otimizada de uma ligação para cenários de modelo, análoga a uma ligação construída com {Binding RelativeSource={RelativeSource TemplatedParent}}.
TemplateBinding é útil para vincular partes do modelo às propriedades do controle. Por exemplo, cada controle tem uma BorderThickness propriedade. Use a TemplateBinding para gerenciar qual elemento no modelo é afetado por essa configuração de controle.
ContentControl e ItemsControl
Se um ContentPresenter for declarado no ControlTemplate de um ContentControl, o ContentPresenter irá automaticamente ligar-se às propriedades ContentTemplate e Content. Da mesma forma, um ItemsPresenter que está no ControlTemplate de um ItemsControl ligar-se-á automaticamente às propriedades ItemTemplate e Items.
Modelos de dados
Neste aplicativo de exemplo, há um ListBox controle vinculado a uma lista de fotos.
<ListBox ItemsSource="{Binding Source={StaticResource MyPhotos}}"
Background="Silver" Width="600" Margin="10" SelectedIndex="0"/>
Atualmente, isso ListBox se parece com o seguinte.
A maioria dos controles tem algum tipo de conteúdo, e esse conteúdo geralmente vem de dados aos quais você está vinculado. Neste exemplo, os dados são a lista de fotos. No WPF, você usa a DataTemplate para definir a representação visual de dados. Basicamente, o que você coloca em um DataTemplate determina a aparência dos dados no aplicativo renderizado.
Em nosso aplicativo de exemplo, cada objeto personalizado Photo tem uma Source propriedade do tipo string que especifica o caminho do arquivo da imagem. Atualmente, os objetos de foto aparecem como caminhos de arquivo.
public class Photo
{
public Photo(string path)
{
Source = path;
}
public string Source { get; }
public override string ToString() => Source;
}
Public Class Photo
Sub New(ByVal path As String)
Source = path
End Sub
Public ReadOnly Property Source As String
Public Overrides Function ToString() As String
Return Source
End Function
End Class
Para que as fotos apareçam como imagens, crie um DataTemplate como recurso.
<Window.Resources>
<!-- .... other resources .... -->
<!--DataTemplate to display Photos as images
instead of text strings of Paths-->
<DataTemplate DataType="{x:Type local:Photo}">
<Border Margin="3">
<Image Source="{Binding Source}"/>
</Border>
</DataTemplate>
</Window.Resources>
Observe que a DataType propriedade é semelhante à TargetType propriedade do Style. A sua DataTemplate estiver na seção de recursos, ao especificar a propriedade DataType para um tipo e omitir um x:Key, o DataTemplate será aplicado sempre que esse tipo surgir. Você tem sempre a opção de atribuir o DataTemplate com um x:Key e depois defini-lo como um StaticResource para propriedades que aceitam tipos DataTemplate, como a propriedade ItemTemplate ou a propriedade ContentTemplate.
Essencialmente, o DataTemplate exemplo acima define que sempre que há um Photo objeto, ele deve aparecer como um Image dentro de um Border. Com isso DataTemplate, nosso aplicativo agora se parece com isso.
O modelo de modelagem de dados fornece outros recursos. Por exemplo, se você estiver exibindo dados de coleção que contenham outras coleções usando um HeaderedItemsControl tipo como a Menu ou a TreeView, há o HierarchicalDataTemplate. Outro recurso de modelagem de dados é o DataTemplateSelector, que permite que você escolha um DataTemplate para usar com base na lógica personalizada. Para obter mais informações, consulte Visão geral de modelagem de dados, que fornece uma discussão mais aprofundada dos diferentes recursos de modelagem de dados.
Acionadores
Um gatilho define propriedades ou inicia ações, como uma animação, quando um valor de propriedade é alterado ou quando um evento é gerado.
Style, ControlTemplatee DataTemplate todos têm uma Triggers propriedade que pode conter um conjunto de gatilhos. Existem vários tipos de gatilhos.
PropertyTriggers
Um Trigger que define valores de propriedade ou inicia ações com base no valor de uma propriedade é chamado de gatilho de propriedade.
Para demonstrar como usar gatilhos de propriedade, pode tornar cada ListBoxItem parcialmente transparente, a menos que seja selecionado. O estilo a seguir define o Opacity valor de a ListBoxItem como 0.5. Quando a IsSelected propriedade é true, no entanto, o Opacity é definido como 1.0.
<Window.Resources>
<!-- .... other resources .... -->
<Style TargetType="ListBoxItem">
<Setter Property="Opacity" Value="0.5" />
<Setter Property="MaxHeight" Value="75" />
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Trigger.Setters>
<Setter Property="Opacity" Value="1.0" />
</Trigger.Setters>
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
Este exemplo usa a Trigger para definir um valor de propriedade, mas observe que a Trigger classe também tem as propriedades e EnterActions que permitem que um gatilho ExitActions execute ações.
Observe que a propriedade MaxHeight de ListBoxItem está definida como 75. Na ilustração a seguir, o terceiro item é o item selecionado.
EventTriggers e Storyboards
Outro tipo de gatilho é o EventTrigger, que inicia um conjunto de ações com base na ocorrência de um evento. Por exemplo, os objetos a seguir EventTrigger especificam que, quando o ponteiro do rato entra no ListBoxItem, a propriedade MaxHeight é animada para um valor de 90 durante um período de 0.2 segundos. Quando o mouse se afasta do item, a propriedade retorna ao valor original por um período de 1 segundo. Observe como não é necessário especificar um To valor para a MouseLeave animação. Isso ocorre porque a animação é capaz de acompanhar o valor original.
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Trigger.Setters>
<Setter Property="Opacity" Value="1.0" />
</Trigger.Setters>
</Trigger>
<EventTrigger RoutedEvent="Mouse.MouseEnter">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Duration="0:0:0.2"
Storyboard.TargetProperty="MaxHeight"
To="90" />
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
<EventTrigger RoutedEvent="Mouse.MouseLeave">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Duration="0:0:1"
Storyboard.TargetProperty="MaxHeight" />
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Style.Triggers>
Para obter mais informações, consulte a visão geral do Storyboards.
Na ilustração a seguir, o mouse está apontando para o terceiro item.
MultiTriggers, DataTriggers e MultiDataTriggers
Além de Trigger e EventTrigger, existem outros tipos de gatilhos. MultiTrigger Permite definir valores de propriedade com base em várias condições. Você usa DataTrigger e MultiDataTrigger quando a propriedade da sua condição está vinculada a dados.
Estados visuais
Os controles estão sempre em um estado específico. Por exemplo, quando o mouse se move sobre a superfície de um controle, o controle é considerado como estando em um estado comum de MouseOver. Um controle sem um estado específico é considerado como estando no estado comum Normal . Os estados são divididos em grupos, e os estados mencionados anteriormente fazem parte do grupo CommonStatesestadual. A maioria dos controlos tem dois grupos de estado: CommonStates e FocusStates. De cada grupo de estados aplicado a um controle, um controle está sempre em um estado de cada grupo, como CommonStates.MouseOver e FocusStates.Unfocused. No entanto, um controle não pode estar em dois estados diferentes dentro do mesmo grupo, como CommonStates.Normal e CommonStates.Disabled. Aqui está uma tabela de estados que a maioria dos controles reconhece e usa.
| Nome do VisualState | Nome do VisualStateGroup | Descrição |
|---|---|---|
Normal |
CommonStates |
O estado padrão. |
MouseOver |
CommonStates |
O ponteiro do mouse é posicionado sobre o controle. |
Pressed |
CommonStates |
O botão de controlo é pressionado. |
Disabled |
CommonStates |
O controle está desativado. |
Focused |
FocusStates |
O comando tem foco. |
Unfocused |
FocusStates |
O controlo não está focado. |
Ao definir um System.Windows.VisualStateManager no elemento raiz de um modelo de controlo, pode-se disparar animações quando um controlo entra em um estado específico. O VisualStateManager especifica quais combinações de VisualStateGroup e VisualState a serem monitorizadas. Quando o controle entra em um estado observado, a animação definida pelo VisualStateManager é iniciada.
Por exemplo, o código XAML a seguir observa o CommonStates.MouseOver estado para animar a cor de preenchimento do elemento chamado backgroundElement. Quando o controle retorna ao CommonStates.Normal estado, a cor de preenchimento do elemento nomeado backgroundElement é restaurada.
<ControlTemplate x:Key="roundbutton" TargetType="Button">
<Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup Name="CommonStates">
<VisualState Name="Normal">
<ColorAnimation Storyboard.TargetName="backgroundElement"
Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)"
To="{TemplateBinding Background}"
Duration="0:0:0.3"/>
</VisualState>
<VisualState Name="MouseOver">
<ColorAnimation Storyboard.TargetName="backgroundElement"
Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)"
To="Yellow"
Duration="0:0:0.3"/>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
...
Para obter mais informações sobre storyboards, consulte Visão geral do Storyboards.
Recursos e temas partilhados
Um aplicativo WPF típico pode ter vários recursos de interface do usuário que são aplicados em todo o aplicativo. Coletivamente, esse conjunto de recursos pode ser considerado o tema do aplicativo. O WPF fornece suporte para empacotar recursos da interface do usuário como um tema usando um dicionário de recursos que é encapsulado como a ResourceDictionary classe.
Os temas do WPF são definidos usando o mecanismo de estilo e modelagem que o WPF expõe para personalizar os visuais de qualquer elemento.
Os recursos do tema WPF são armazenados em dicionários de recursos incorporados. Esses dicionários de recursos devem ser incorporados dentro de uma assemblagem assinada e podem ser incorporados na mesma assemblagem que o próprio código ou em assemblagens lado a lado. Para PresentationFramework.dll, o assembly que contém controles WPF, recursos de temas estão numa série de assemblies adjacentes.
O tema torna-se o último lugar a procurar quando se procura o estilo de um elemento. Normalmente, a pesquisa começará subindo a árvore de elementos em busca de um recurso apropriado, depois procurará na coleção de recursos do aplicativo e, finalmente, consultará o sistema. Isso dá aos desenvolvedores de aplicativos a chance de redefinir o estilo de qualquer objeto no nível da árvore ou do aplicativo antes de alcançar o tema.
Você pode definir dicionários de recursos como arquivos individuais que permitem reutilizar um tema em vários aplicativos. Você também pode criar temas permutáveis definindo vários dicionários de recursos que fornecem os mesmos tipos de recursos, mas com valores diferentes. Redefinir esses estilos ou outros recursos no nível do aplicativo é a abordagem recomendada para aplicar capa em um aplicativo.
Para compartilhar um conjunto de recursos, incluindo estilos e modelos, entre aplicativos, você pode criar um arquivo XAML e definir um ResourceDictionary que inclua referência a um shared.xaml arquivo.
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Shared.xaml" />
</ResourceDictionary.MergedDictionaries>
É a partilha de shared.xaml, que por si só define um ResourceDictionary contendo um conjunto de recursos de estilo e pincel, que permite aos controlos numa aplicação terem uma aparência consistente.
Para obter mais informações, consulte Dicionários de recursos mesclados.
Se você estiver criando um tema para seu controle personalizado, consulte a seção Definindo recursos no nível do tema da visão geral da criação do controle.
Ver também
.NET Desktop feedback