current position:Home>WPF - Styles and Templates

WPF - Styles and Templates

2022-08-06 08:41:52MelonSuika


每次写blogI must be having some actual problem.And this time the problem,And post title is not particularly big.Because in the last article I talked about custom calendar controls(Calendar)的事,in my changeCalendarDayButtonStyle的过程中,我发现默认的Styleappeared in a large number ofVisualState标签.But as mentioned above,One's ownWPFProgrammers may be rightVisualStateRelated classes will also feel unfamiliar,更何况我呢.于是我决定,对VisualStateRelated classes.

I open the Microsoft official website,搜了下VisualState,首先在Windows App SDKThe content of the saw it,But I am nowWPFmet it in.Although the content looks similar,But I still want to beWPFfound it in the related articles of.So I read a few more articles.在WPF的《Styles and Templates》seen in the chapterVisualState的出现.但是,This chapter mainly introduces styles and templates.,VisualStateThe content is only a little.那怎么办?我想了想,Anyway, the styles and templates have not been systematically learned.,I'm already using it,不如借此机会,also study hard.


WPFStyles and Templates are a set of features that allow developers and designers to create visually striking and consistent looks for their products.When customizing the appearance of a program,You want a powerful styling and template model,They can support within the program, and program maintenance and sharing between appearance.WPFprovides such a model.

two long sentences,意思很简单,样式(style)和模板(Template)is a tool to generalize the appearance.

WPFAnother feature of the style model is that it represents(Presentation)与逻辑(logic)的分离.

Indicates that can be considered proceduralUI,Logic can be thought of as business logic(后台逻辑).
在传统WinForms中,Drag and drop controls on the interface,Control background processing logic,And sometimes there will be changes in logic controls the appearance of the code,This is the representation and logic to mix up with.such a mixed way in small projects ordemo中,确实很方便,But for the division of labor、For maintainability,For the structure of the entire program,But a big discount.So separating presentation and logic is a manifestation of progress.

Designers can just useXAMLto handle the appearance of the application,而开发人员可以使用C#或VBto handle programming logic.(This idea is quite ideal in China.,反正据我了解,大部分公司WPFThe front and back of the development are still done by the same group of people.But making the layering of the program clearer does achieve.)

This article focuses on the styling and templating aspects of the program,Do not discuss any of the concept of data binding.(So you better have someWPF基础,至少对Binding有个大概的概念)

and before school,best resource(Resource)了解一下,Because resources can reuse styles and templates.

1. 示例程序 Sample

The example in this article is a simple photo-based browsing program,如下图所示:
This simple photo sample program uses styles and templates to create a visually good user experience.The example has twoTextBlockelement and a bound to an image listListBox控件.

2. 样式 Style

你可以将Style(样式)Treated as a set of attribute values,It is a convenience method that can be applied to multiple can derive fromFrameworkElement或FrameworkContentElementUse of any elementStyle,比如Window或Button.

The most common way to declare a style is inXAML文件中的ResourcesUse as a resource in the segment.Because styles are resources,so they follow all the rules that apply to the resource.简单说,where styles are declared affects styles applied there.例如,if you are in the program(app)定义XAMLThe root element of the file declares aStyle,该Stylecan be used anywhere in the program.

例如,下面的XAML代码为TextBlockTwo styles are declared,one automatically applies to allTextBlock元素,Another must be explicitly quoted.

<!--在WindowAdd styles to the element's resources,and specify the target,This is a very common way-->
    <!-- .... 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-->
    <!--BaseOn有继承的意味,is to modify the original style-->
    <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>

Here is an example using the declarative style above:

    <TextBlock Style="{
        StaticResource TitleText}" Name="textblock1">My Pictures</TextBlock>
    <TextBlock>Check out my new pictures!</TextBlock>


3. 控件模板 ControlTemplates

在WPF中,控件的ControlTemplateDefines the appearance of the controls.You can do this by defining newControlTemplateand assign it to the specified control to change the structure and appearance of the control.在许多情况下,Templates give you enough flexibility,so that you don't need to write custom controls.

Each control has aControl.Template的默认模板.Templates connect the visual appearance of a control with the functionality of the control.因为是在XAMLdefined in the template,So you can change the appearance of the control without writing any code.Each template is designed for a specific control,比如Button.

通常,你可以在XAML文件的ResourcesPart of the template declaration for the resource.It applies the same rules as all resources.

Control templates are much more complex than styles.This is because the control template overrides the visual appearance of the entire control(visual appearance),while styles just change the properties of existing controls.不过,Because the template of the control is over-setControl.Templateproperties to apply,So you can use styles to define or set a template.

尽管StyleIs aimed at the properties of the controls,
而Templateis to rewrite the entire control structure,
At this point, templates are obviously more complicated than styles,But the template itself is also a property of the control,所以StyleChanges can also be specifiedControl.Template,这个角度来看,It seems that no one is necessarily more complicated than the other.?

Designers(设计器)Usually allows you to create a copy of an existing template and modify it.例如.在Visual Studio WPF设计器中,选择一个CheckBox控件,Then right-click and select edit template>创建一个副本.One operation will generate the style that defines the template.

This method is often used to modify some built-in or third-party controls,because these controls are usually more complex,It takes time to implement from scratch and make changes,So you can generate their styles by doing the above,and then change some of them.

<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">
            <ControlTemplate TargetType="{x:Type CheckBox}">
                <Grid x:Name="templateRoot" Background="Transparent" SnapsToDevicePixels="True">
                        <ColumnDefinition Width="Auto"/>
                        <ColumnDefinition Width="*"/>
                    <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"/>
                    <ContentPresenter x:Name="contentPresenter" Grid.Column="1" Focusable="False" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                    <Trigger Property="HasContent" Value="true">
                        <Setter Property="FocusVisualStyle" Value="{StaticResource OptionMarkFocusVisual1}"/>
                        <Setter Property="Padding" Value="4,-1,0,0"/>

... content removed to save space ...

Editing a copy of the template is a great way to see how the template works.compared to creating a new blank template,It's obviously easier to edit templates and change parts of the visual representation.

Many controls seem difficult to implement,After you make a copy of it, you can see its internal structure at a glance,So this method is also a good way to learn control implementation ideas.

3.1. TemplateBinding

你可能已经注意到,The template resource defined in the previous section usesTemplateBinding标记拓展.TemplateBindingis an optimized form of binding for template scenarios,类似于使用

{Binding RelativeSource = {RelativeSource TemplatedParent}}

Constructed binding.TemplateBindingProperties used to bind parts of templates to controls.例如,每个控件都有一个BorderThickness属性.使用TemplateBindingTo manage the affected by the control set element in the template.

3.2. ContentControl和ItemsControl


4. 数据模板 DataTemplates

在本例的程序中,有一个ListBox控件,it binds a list of photos.

<ListBox ItemsSource="{Binding Source={StaticResource MyPhotos}}" Background="Silver" Width="600" Margin="10" SelectedIndex="0"/>

该ListBoxNow look like this:
Most controls have some type of content,And that usually comes from the data you bind.在本例中,Data is a list of photos.在WPF中,使用DataTemplateTo define the visual representation of data(即外观).基本地,你放入DataTemplateThe content determines how the data will look in the renderer.

在示例程序中,每个自定义的Photo对象都有一个string类型的Source属性,Path to specify the image file.现在,Image object as a file path and rendering.

public class Photo
    public Photo(string path)
        Source = path;

    public string Source {
     get; }

    public override string ToString() => Source;

In order for the photo to be displayed as an image,你需要创建一个DataTemplate作为资源.

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

注意,DataType属性类似于Style的TargetType属性.如果你的DataTemplate在Resources中,when you specify a typeDataTypeattribute and omitx:Key时,as long as the type appears,就会应用DataTemplate.当然,You can always choose to usex:Key来分配DataTemplate,然后将它设置给StaticResource(用于接受DataTemplate类型的属性,例如,ItemTemplate属性或ContentTemplate属性).

本质上来讲,上面示例中的DataTemplate定义了“只要有Photo对象出现,it should behave asBorder中的Image”.在该DataTemplate中,The program now looks like this:
数据模板(DataTemplate)The model provides other features.例如,如果你正在使用HeaderedItemsControl类型(如Menu或TreeView)to display collection data that contains other collections,则会有HierarchicalDataTemplate.Another data template feature isDataTemplateSelector,It allows you to choose which one to use based on custom logicDataTemplate.

5. 触发器 Triggers

When a property value changes or an event is raised,trigger(触发器)will set properties or initiate actions,例如动画.Style、ControlTemplate和DataTemplatehas a property that can contain a set of triggersTriggers.There are many types of triggers.

5.1. PropertyTriggers

Set a property value or initiate an action based on the property's value(action)triggers are called property triggers,它就用Trigger来表示.

To demonstrate how to use property triggers,可以让ListBoxItem部分透明(unless it is selected).The following style willListBoxItem的Opacity(不透明度,1为不透明,0为全透明)设置为0.5;当IsSelected属性为true时,不透明度设为1.0.

    <!-- .... 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>

本例使用一个Trigger来设置属性值,但是要注意,Trigger类还有EnterActions和ExitActions属性,These properties enable triggers to perform actions.

注意,ListBoxItem的MaxHeight属性被设置为75.在下图中,The third item is selected.


5.2. EventTriggers和Storyboards

Another type of trigger isEventTrigger(事件触发器),It initiates a set of actions based on the occurrence of an event.例如,下面的EventTriggerThe object specifies when the mouse pointer entersListBoxItem区域时,MaxHeight属性在0.2sanimation will occur inside,值变为90.when the mouse leaves the option,属性会在1sBack to the initial value.注意,不需要为MouseLeaveThe animation specifies the target value,Because the animation can track itself to the original value.

    <Trigger Property="IsSelected" Value="True">
            <Setter Property="Opacity" Value="1.0" />
    <EventTrigger RoutedEvent="Mouse.MouseEnter">
                    <DoubleAnimation Duration="0:0:0.2" Storyboard.TargetProperty="MaxHeight" To="90" />
    <EventTrigger RoutedEvent="Mouse.MouseLeave">
                    <DoubleAnimation Duration="0:0:1" Storyboard.TargetProperty="MaxHeight" />

在下图中,The mouse points to the third item:

5.3. MultiTriggers、DataTriggers和MultiDataTriggers

除了Trigger和EventTrigger,There are other types of triggers.MultiTriggerAllows you to set property values ​​based on multiple conditions.When the property of the condition is data bound(data-bound),可以使用DataTrigger和MultiDataTrigger.

6. 视觉状态 Visual States

Controls are always in a specific state(specific state)中的.例如,When the mouse moves over the surface of the control,the control is considered to be inMouseOver的常见状态.Controls without a specific state are considered normalNormal状态.Status can be grouped,The aforementioned states areCommonStatespart of this state group.Most controls have two state groups:CommonStates和 each state group applied to the control,Controls are always in one state per group,例如CommonStates.MouseOver和FocusStates.Unfocused.A control can not in the same group in the two different state,For example not inCommonStates.Normal和CommonStates.Disabled中.Below is the state table most controls recognize and use:

VisualState NameVisualStateGroup Name描述
MouseOverCommonStatesmouse pointer over control
FocusedFocusStatescontrol has focus
UnfocusedFocusStatesControl has no focus

By defining on the root element of the control templateSystem.Windows.VisualStateManager,Animations can be triggered when a control enters a specific state.VisualStateManagerdeclared to be monitoredVisualStateGroup和VisualState的组合.When the control enters the watch state,VisualStateManagerThe defined animation will start.

例如,下面的XAMLcode monitoringCommonStates.MouseOver状态,使得名为backgroundElementThe fill color of the element is animated.When the control returns toCommonStates.Normal状态时,恢复backgroundElementelement's fill color.

<ControlTemplate x:Key="roundbutton" TargetType="Button">
            <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 Name="MouseOver">
                    <ColorAnimation Storyboard.TargetName="backgroundElement" Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)" To="Yellow" Duration="0:0:0.3"/>


7. Shared resources and subjects Shared resources和themes

一个典型的WPFA program may have multipleUI资源.总的来说,This set of resources can be thought of as the body of the program.WPFby using the package asResourceDictionaryclass resource dictionary,来支持将UIResource packaging as the theme.

WPFThemes are defined by using styles and templating mechanisms,WPFThese mechanisms are exposed to customize the visual effects of any element.

WPFPrincipal resources are stored in an embedded resource dictionary.These resource dictionaries must be embedded in the signed assembly,and can be embedded in the same assembly as the code itself,Can also be embedded in parallel(side-by-side)的程序集中.PresentationFramework.dll,该程序集包含了WPF控件,Theme resources are in a series of side-by-side assemblies.

When searching for the style of an element,Subject will be the last location to look for.通常情况下,The search will crawl up the element tree to find the appropriate resource,若找不到,then find the resource set of the program,Finally find the system.This gives program developers a chance,make the search before reaching the topic,Can redefine styles for any object on the tree or programmatically.

You can define resource dictionaries as separate files,This allows you to reuse a theme in multiple programs.You can also create switchable themes by defining multiple resource dictionaries,These resource dictionaries provide the same type of resources,但是值不同.Redefining styles or other resources at the application level is the recommended approach for application skinning.

To share a set of resources including styles and templates across programs,可以创建一个XAML文件,并定义一个ResourceDictionary,The resource dictionary contains theshare.xaml的引用.

  <ResourceDictionary Source="Shared.xaml" />

它是share.xaml的共享,It itself defines a set of style and brush resourcesResourceDictionary,Gives the program's controls a consistent look.


通过本文的学习,revisited the style、控件模板、Data Templates and Triggers,Visual state、Have an initial understanding of the concepts of shared resources and topics.

copyright notice
author[MelonSuika],Please bring the original link to reprint, thank you.

Random recommended