通过创建 ControlTemplate 自定义现有控件的外观Customizing the Appearance of an Existing Control by Creating a ControlTemplate

ControlTemplate 指定视觉结构和控件的视觉行为。A ControlTemplate specifies the visual structure and visual behavior of a control. 可以通过向控件提供一个新的ControlTemplate 对控件外观进行自定义。You can customize the appearance of a control by giving it a new ControlTemplate. 创建 ControlTemplate 时,仅替换现有控件的外观,而不会更改其功能。When you create a ControlTemplate, you replace the appearance of an existing control without changing its functionality. 例如,可在应用程序中将按钮设置为圆形而不是默认的方形,但按钮仍将引发 Click 事件。For example, you can make the buttons in your application round instead of the default square shape, but the button will still raise the Click event.

本主题介绍了ControlTemplate的各个部分, 演示如何创建一个简单ControlTemplateButton, 并说明如何理解控件的控制协定, 以便您可以自定义控件的外观。This topic explains the various parts of a ControlTemplate, demonstrates creating a simple ControlTemplate for a Button, and explains how to understand the control contract of a control so that you can customize its appearance. 由于你在中ControlTemplate创建XAMLXAML了, 因此你可以在不编写任何代码的情况下更改控件的外观。Because you create a ControlTemplate in XAMLXAML, you can change a control's appearance without writing any code. 还可以使用设计器(如 Microsoft Expression Blend)创建自定义控件模板。You can also use a designer, such as Microsoft Expression Blend, to create custom control templates. 本主题演示了XAMLXAML自定义外观Button的中的示例, 并列出了本主题末尾的完整示例。This topic shows examples in the XAMLXAML that customize the appearance of a Button and lists the complete example at the end of the topic. 有关使用 Expression Blend 的详细信息,请参阅设置支持模板的控件的样式For more information about using Expression Blend, see Styling a control that supports templates.

下图显示了一个Button , 它ControlTemplate使用在本主题中创建的。The following illustrations show a Button that uses the ControlTemplate that is created in this topic.

带有自定义控件模板的按钮。A button with a custom control template.
使用自定义控件模板的按钮A button that uses a custom control template

带有红色边框的按钮。A button with a red border.
使用自定义控件模板并将鼠标指针悬停在上方的按钮A button that uses a custom control template and has the mouse pointer over it

系统必备Prerequisites

本主题假设用户了解如何创建和使用控件中讨论的控件和样式。This topic assumes that you understand how to create and use controls and styles as discussed in Controls. 本主题中讨论的概念适用于从Control类继承的元素, 但除外。 UserControlThe concepts discussed in this topic apply to elements that inherit from the Control class, except for the UserControl. 不能将应用ControlTemplate UserControl于。You cannot apply a ControlTemplate to a UserControl.

何时应创建 ControlTemplateWhen You Should Create a ControlTemplate

控件具有许多属性 (例如BackgroundForegroundFontFamily), 您可以将其设置为指定控件外观的不同方面, 但您可以通过设置这些属性进行的更改将受到限制。Controls have many properties, such as Background, Foreground, and FontFamily, that you can set to specify different aspects of the control's appearance, but the changes that you can make by setting these properties are limited. 例如, 可以将的Foreground属性设置为蓝色, FontStyle将设置为斜体CheckBoxFor example, you can set the Foreground property to blue and FontStyle to italic on a CheckBox.

如果没有为控件创建新ControlTemplate的功能, 则基于每个WPFWPF应用程序中的所有控件都将具有相同的常规外观, 这将限制创建具有自定义外观的应用程序的能力。Without the ability to create a new ControlTemplate for controls, all controls in every WPFWPF-based application would have the same general appearance, which would limit the ability to create an application with a custom look and feel. 默认情况下, CheckBox每个都具有类似的特征。By default, every CheckBox has similar characteristics. 例如, 的CheckBox内容始终位于选择指示器的右侧, 并且复选标记始终用于指示CheckBox已选择。For example, the content of the CheckBox is always to the right of the selection indicator, and the check mark is always used to indicate that the CheckBox is selected.

ControlTemplate如果要自定义控件的外观, 而不是控件上的其他属性将执行的操作, 请创建。You create a ControlTemplate when you want to customize the control's appearance beyond what setting the other properties on the control will do. 在的示例CheckBox中, 假设您希望复选框的内容位于选择指示器之上, 并且您希望 X 指示CheckBox选中了。In the example of the CheckBox, suppose that you want the content of the check box to be above the selection indicator and you want an X to indicate that the CheckBox is selected. 在的中ControlTemplate CheckBox指定这些更改。You specify these changes in the ControlTemplate of the CheckBox.

下图显示了一个CheckBox使用默认值ControlTemplate的。The following illustration shows a CheckBox that uses a default ControlTemplate.

具有默认控件模板的复选框。A checkbox with the default control template.
一个具有默认控件模板的复选框A CheckBox that uses the default control template

下图显示了一个CheckBox , 它使用自ControlTemplate定义将CheckBox上的内容置于CheckBox选择指示器上方, 并在选择时显示 X。The following illustration shows a CheckBox that uses a custom ControlTemplate to place the content of the CheckBox above the selection indicator and displays an X when the CheckBox is selected.

带有自定义控件模板的复选框。A checkbox with a custom control template.
一个具有自定义控件模板的复选框A CheckBox that uses a custom control template

在此示例中, 的与相对较为复杂, 因此本主题使用Button的是ControlTemplate为创建的一个更简单的示例。 ControlTemplate CheckBoxThe ControlTemplate for the CheckBox in this sample is relatively complex, so this topic uses a simpler example of creating a ControlTemplate for a Button.

更改控件的可视结构Changing the Visual Structure of a Control

WPFWPF中, 控件通常是复合FrameworkElement对象。In WPFWPF, a control is often a composite FrameworkElement objects. 当你创建ControlTemplate时, 将组合FrameworkElement对象以生成单个控件。When you create a ControlTemplate, you combine FrameworkElement objects to build a single control. 只能有一个FrameworkElement作为其根元素。 ControlTemplateA ControlTemplate must have only one FrameworkElement as its root element. 根元素通常包含其他FrameworkElement对象。The root element usually contains other FrameworkElement objects. 对象组合构成控件的可视结构。The combination of objects makes up the control's visual structure.

下面的示例Button为创建了ControlTemplate一个自定义。The following example creates a custom ControlTemplate for the Button. 创建的可视结构ButtonControlTemplateThe ControlTemplate creates the visual structure of the Button. 在按钮上方移动鼠标指针或单击它时,此示例不会更改按钮的外观。This example does not change the button's appearance when you move the mouse pointer over it or click it. 本主题后面部分将讨论当按钮处于其他状态时更改它的外观。Changing the button's appearance when it is in a different state is discussed later in this topic.

在本示例中,可视结构包括以下部分:In this example, the visual structure consists of the following parts:

<ControlTemplate TargetType="Button">
  <Border Name="RootElement">

    <!--Create the SolidColorBrush for the Background 
        as an object elemment and give it a name so 
        it can be referred to elsewhere in the
        control template.-->
    <Border.Background>
      <SolidColorBrush x:Name="BorderBrush" Color="Black"/>
    </Border.Background>

    <!--Create a border that has a different color
        by adding smaller grid. The background of 
        this grid is specificied by the button's 
        Background property.-->
    <Grid Margin="4" Background="{TemplateBinding Background}">

      <!--Use a ContentPresenter to display the Content of
          the Button.-->
      <ContentPresenter
        HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
        VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
        Margin="4,5,4,4" />
    </Grid>

  </Border>
</ControlTemplate>

使用 TemplateBinding 保留控件属性的功能Preserving the Functionality of a Control's Properties by Using TemplateBinding

创建新ControlTemplate的时, 您仍可能想要使用公共属性来更改控件的外观。When you create a new ControlTemplate, you still might want to use the public properties to change the control's appearance. TemplateBinding标记扩展将中ControlTemplate元素的属性绑定到由控件定义的公共属性。The TemplateBinding markup extension binds a property of an element that is in the ControlTemplate to a public property that is defined by the control. 使用 TemplateBinding 时,可让控件属性用作模板参数。When you use TemplateBinding, you enable properties on the control to act as parameters to the template. 换言之,设置控件属性后,该值将传递到包含 TemplateBinding 的元素。That is, when a property on a control is set, that value is passed on to the element that has the TemplateBinding on it.

下面的示例重复了前面示例的部分, 该部分使用TemplateBinding标记扩展将中ControlTemplate元素的属性绑定到由按钮定义的公共属性。The following example repeats the part of the preceding example that uses the TemplateBinding markup extension to bind properties of elements that are in the ControlTemplate to public properties that are defined by the button.

<Grid Margin="4" Background="{TemplateBinding Background}">

  <!--Use a ContentPresenter to display the Content of
      the Button.-->
  <ContentPresenter
    HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
    VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
    Margin="4,5,4,4" />
</Grid>

在此示例中, Grid将其Panel.Background属性模板绑定到Control.BackgroundIn this example, the Grid has its Panel.Background property template bound to Control.Background. 由于Panel.Background是绑定了模板, 因此你可以创建多个使用相同ControlTemplate的按钮, Control.Background并在每个按钮上将设置为不同的值。Because Panel.Background is template bound, you can create multiple buttons that use the same ControlTemplate and set the Control.Background to different values on each button. 如果Control.Background未将模板绑定到ControlTemplate中的元素的属性, 则设置Control.Background按钮的将不会影响按钮的外观。If Control.Background was not template bound to a property of an element in the ControlTemplate, setting the Control.Background of a button would have no impact on the button's appearance.

请注意,两个属性的名称不必一样。Note that the names of the two properties do not need to be identical. 在前面的示例中, Control.HorizontalContentAlignmentButton属性FrameworkElement.HorizontalAlignment是绑定到的ContentPresenter属性的模板。In the preceding example, the Control.HorizontalContentAlignment property of the Button is template bound to the FrameworkElement.HorizontalAlignment property of the ContentPresenter. 这样可以水平放置按钮的内容。This enables the content of the button to be positioned horizontally. ContentPresenter没有名为HorizontalContentAlignment的属性, 但Control.HorizontalContentAlignment可以绑定到FrameworkElement.HorizontalAlignmentContentPresenter does not have a property named HorizontalContentAlignment, but Control.HorizontalContentAlignment can be bound to FrameworkElement.HorizontalAlignment. 在通过模板绑定属性时,请确保目标属性和源属性属于同一类型。When you template bind a property, be sure that the target and source properties are the same type.

Control类定义一些属性, 控件模板必须使用这些属性才能在设置控件时对控件产生影响。The Control class defines several properties that must be used by the control template to have an effect on the control when they are set. ControlTemplate使用属性的方式取决于属性。How the ControlTemplate uses the property depends on the property. ControlTemplate必须通过以下方式之一使用属性:The ControlTemplate must use the property in one of the following ways:

下表列出了由Control类中的控件继承的视觉对象属性。The following table lists the visual properties inherited by a control from the Control class. 它还指示控件的默认控件模板是使用继承的属性值,还是必须通过模板绑定。It also indicates whether the default control template of a control uses the inherited property value or if it must be template bound.

PropertyProperty 使用方法Usage method
Background 模板绑定Template binding
BorderThickness 模板绑定Template binding
BorderBrush 模板绑定Template binding
FontFamily 属性继承或模板绑定Property inheritance or template binding
FontSize 属性继承或模板绑定Property inheritance or template binding
FontStretch 属性继承或模板绑定Property inheritance or template binding
FontWeight 属性继承或模板绑定Property inheritance or template binding
Foreground 属性继承或模板绑定Property inheritance or template binding
HorizontalContentAlignment 模板绑定Template binding
Padding 模板绑定Template binding
VerticalContentAlignment 模板绑定Template binding

该表仅列出从Control类继承的视觉对象属性。The table lists only the visual properties inherited from the Control class. 除了表中列出的属性以外, 控件还可以继承父框架元素DataContextLanguage的、 TextDecorations和属性。Apart from the properties listed in the table, a control may also inherit the DataContext, Language, and TextDecorations properties from the parent framework element.

此外ContentPresenter , 如果位于的ControlTemplateContentControl, ContentPresenter则将自动绑定到ContentTemplateContent属性。Also, if the ContentPresenter is in the ControlTemplate of a ContentControl, the ContentPresenter will automatically bind to the ContentTemplate and Content properties. 同样ItemsPresenter , 位于的ItemsControl ControlTemplate中的将自动绑定到ItemsItemsPresenter属性。Likewise, an ItemsPresenter that is in the ControlTemplate of an ItemsControl will automatically bind to the Items and ItemsPresenter properties.

下面的示例创建了两个按钮, ControlTemplate这些按钮使用前面的示例中定义的。The following example creates two buttons that use the ControlTemplate defined in the preceding example. 该示例设置每BackgroundForeground按钮的FontSize 、和属性。The example sets the Background, Foreground, and FontSize properties on each button. 设置属性会产生影响, 因为它是中的ControlTemplate模板绑定。 BackgroundSetting the Background property has an effect because it is template bound in the ControlTemplate. 即使和Foreground FontSize属性不是模板绑定的, 设置它们也有影响, 因为它们的值是继承的。Even though the Foreground and FontSize properties are not template bound, setting them has an effect because their values are inherited.

<StackPanel>
  <Button Style="{StaticResource newTemplate}" 
          Background="Navy" Foreground="White" FontSize="14"
          Content="Button1"/>

  <Button Style="{StaticResource newTemplate}" 
          Background="Purple" Foreground="White" FontSize="14"
          Content="Button2" HorizontalContentAlignment="Left"/>
</StackPanel>

前面的示例生成类似于下图的输出。The preceding example produces output that is similar to the following illustration.

两个按钮, 一个蓝色, 一个紫色。Two buttons, one blue and one purple.
背景色不同的两个按钮Two buttons with different background colors

根据控件状态更改它的外观Changing the Appearance of a Control Depending on Its State

显示默认外观的按钮与前面示例中按钮的差异在于,默认按钮在处于不同状态时会略有变化。The difference between a button with its default appearance and the button in the preceding example is that the default button subtly changes when it is in different states. 例如,在按下按钮或鼠标指针悬停在它的上方时,默认按钮的外观将发生变化。For example, the default button's appearance changes when the button is pressed, or when the mouse pointer is over the button. 尽管不ControlTemplate会更改控件的功能, 但它确实更改了控件的可视行为。Although the ControlTemplate does not change the functionality of a control, it does change the control's visual behavior. 可视行为描述控件处于某种状态下的外观。A visual behavior describes the control appearance when it is in a certain state. 若要了解控件功能和可视行为之间的差异,请考虑按钮示例。To understand the difference between the functionality and visual behavior of a control, consider the button example. 按钮的功能是在单击Click事件时引发事件, 但按钮的视觉行为是在指向或按下时更改其外观。The button's functionality is to raise the Click event when it is clicked, but the button's visual behavior is to change its appearance when it is pointed to or pressed.

使用VisualState对象可指定控件在处于某种状态时的外观。You use VisualState objects to specify the appearance of a control when it is in a certain state. 包含一个Storyboard , 它更改中的ControlTemplate元素的外观。 VisualStateA VisualState contains a Storyboard that changes the appearance of the elements that are in the ControlTemplate. 无需编写任何代码即可执行此操作, 因为控件的逻辑通过使用VisualStateManager更改状态。You do not have to write any code to make this occur because the control's logic changes state by using the VisualStateManager. 当控件输入VisualState.Name属性指定的状态时, 将Storyboard开始。When the control enters the state that is specified by the VisualState.Name property, the Storyboard begins. 当控件退出状态时, 将Storyboard停止。When the control exits the state, the Storyboard stops.

下面的示例演示VisualState Button当鼠标指针位于其上方时更改的外观。The following example shows the VisualState that changes the appearance of a Button when the mouse pointer is over it. 通过更改的BorderBrush颜色来更改按钮的边框颜色。StoryboardThe Storyboard changes the button's border color by changing the color of the BorderBrush. ControlTemplate如果你引用本主题开头部分的示例, 你将想起, 这SolidColorBrush BorderBrush是分配给BackgroundBorder的名称。If you refer to the ControlTemplate example at the beginning of this topic, you will recall that BorderBrush is the name of the SolidColorBrush that is assigned to the Background of the Border.

<!--Change the border of the button to red when the
    mouse is over the button.-->
<VisualState x:Name="MouseOver">
  <Storyboard>
    <ColorAnimation Storyboard.TargetName="BorderBrush"     
                    Storyboard.TargetProperty="Color"
                    To="Red" />

  </Storyboard>
</VisualState>

该控件负责将各种状态定义为控件协定的一部分,这将在本主题后面的通过了解控件协定自定义其他控件中进行详细讨论。The control is responsible for defining the states as part of its control contract, which is discussed in detail in Customizing Other Controls by Understanding the Control Contract later in this topic. 下表列出了为Button指定的状态。The following table lists the states that are specified for the Button.

VisualState 名称VisualState Name VisualStateGroup 名称VisualStateGroup Name 描述Description
普通Normal CommonStatesCommonStates 默认状态。The default state.
MouseOverMouseOver CommonStatesCommonStates 鼠标指针悬停在控件上方。The mouse pointer is positioned over the control.
已按下Pressed CommonStatesCommonStates 已按下控件。The control is pressed.
已禁用Disabled CommonStatesCommonStates 已禁用控件。The control is disabled.
已设定焦点Focused FocusStatesFocusStates 控件有焦点。The control has focus.
失去焦点Unfocused FocusStatesFocusStates 控件没有焦点。The control does not have focus.

CommonStates Normal MouseOver Pressed定义两个状态组: 组包含、、和Disabled状态。 ButtonThe Button defines two state groups: the CommonStates group contains the Normal, MouseOver, Pressed, and Disabled states. FocusStates 组包含 FocusedUnfocused 状态。The FocusStates group contains the Focused and Unfocused states. 同一状态组中的状态之间相互排斥。States in the same state group are mutually exclusive. 控件在每个组中始终处于一种状态下。The control is always in exactly one state per group. 例如, Button即使鼠标指针未悬停在上, 也可以具有焦点, 因此Focused状态中的Button可以是MouseOverPressedNormal状态。For example, a Button can have focus even when the mouse pointer is not over it, so a Button in the Focused state can be in the MouseOver, Pressed, or Normal state.

将对象VisualState添加到VisualStateGroup对象。You add VisualState objects to VisualStateGroup objects. 将对象VisualStateGroup添加VisualStateGroups到附加属性。You add VisualStateGroup objects to the VisualStateGroups attached property. 下面的VisualState示例定义NormalMouseOverPressed状态的对象, 这些对象都在组中。CommonStatesThe following example defines the VisualState objects for the Normal, MouseOver, and Pressed states, which are all in the CommonStates group. Name每个VisualState的都与上表中的名称匹配。The Name of each VisualState matches the name in the preceding table. 省略 Disabled 状态和 FocusStates 组中的各种状态是为了使示例保持简短,但本主题末尾的完整示例将它们包括在内。The Disabled state and the states in the FocusStates group are omitted to keep the example short, but they are included in the entire example at the end of this topic.

备注

请确保设置VisualStateGroupsFrameworkElement ControlTemplate根的附加属性。Be sure to set the VisualStateGroups attached property on the root FrameworkElement of the ControlTemplate.

<ControlTemplate TargetType="Button">
  <Border Name="RootElement">

    <VisualStateManager.VisualStateGroups>

      <!--Define the states and transitions for the common states.
          The states in the VisualStateGroup are mutually exclusive to
          each other.-->
      <VisualStateGroup x:Name="CommonStates">

        <!--The Normal state is the state the button is in
            when it is not in another state from this VisualStateGroup.-->
        <VisualState x:Name="Normal" />

        <!--Change the SolidColorBrush, BorderBrush, to red when the
            mouse is over the button.-->
        <VisualState x:Name="MouseOver">
          <Storyboard>
            <ColorAnimation Storyboard.TargetName="BorderBrush" 
                            Storyboard.TargetProperty="Color" 
                            To="Red" />
          </Storyboard>
        </VisualState>

        <!--Change the SolidColorBrush, BorderBrush, to Transparent when the
            button is pressed.-->
        <VisualState x:Name="Pressed">
          <Storyboard>
            <ColorAnimation Storyboard.TargetName="BorderBrush" 
                            Storyboard.TargetProperty="Color"
                            To="Transparent"/>
          </Storyboard>
        </VisualState>

        <!--The Disabled state is omitted for brevity.-->
      </VisualStateGroup>
    </VisualStateManager.VisualStateGroups>

    <Border.Background>
      <SolidColorBrush x:Name="BorderBrush" Color="Black"/>
    </Border.Background>

    <Grid Background="{TemplateBinding Background}" Margin="4">
      <ContentPresenter
        HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
        VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
        Margin="4,5,4,4" />
    </Grid>
  </Border>
</ControlTemplate>

前面的示例生成类似于下图的输出。The preceding example produces output that is similar to the following illustrations.

带有自定义控件模板的按钮。A button with a custom control template.
使用正常状态下的自定义控件模板的按钮A button that uses a custom control template in the normal state

带有红色边框的按钮。A button with a red border.
使用鼠标悬停状态下的自定义控件模板的按钮A button that uses a custom control template in the mouse over state

按下的按钮上的边框是透明的。The border is transparent on a pressed button.
使用按下状态下的自定义控件模板的按钮A button that uses a custom control template in the pressed state

若要查找附带在 WPFWPF 中的控件的可视状态,请参阅 Control 样式和模板To find the visual states for controls that are included with WPFWPF, see Control Styles and Templates.

指定控件在状态之间转换时的行为Specifying the Behavior of a Control When It Transitions Between States

在前面的示例中,按钮的外观在用户单击它时也会发生更改,但除非按钮按下整整一秒,否则用户将看不到效果。In the preceding example, the appearance of the button also changes when the user clicks it, but unless the button is pressed for a full second, the user does not see the effect. 默认情况下,动画需要一秒才会发生。By default, the animation takes one second to occur. 由于用户可能会在很少的时间内单击并释放按钮, 因此, 如果您ControlTemplate将处于默认状态, 则视觉反馈将不会生效。Because users are likely to click and release a button in much less time, the visual feedback will not be effective if you leave the ControlTemplate in its default state.

可以通过将对象添加VisualTransition ControlTemplate到来指定动画发生的时间量, 以将控件从一个状态平滑转换到另一个状态。You can specify the amount of time that it takes an animation to occur to smoothly transition a control from one state to another by adding VisualTransition objects to the ControlTemplate. 当你创建VisualTransition时, 你可以指定以下一个或多个:When you create a VisualTransition, you specify one or more of the following:

  • 在状态之间进行转换所需的时间。The time it takes for a transition between states to occur.

  • 在转换的同时,控件外观发生的其他更改。Additional changes in the control's appearance that occur at the time of the transition.

  • 应用于的VisualTransition状态。Which states the VisualTransition is applied to.

指定转换的持续时间Specifying the Duration of a Transition

可以通过设置GeneratedDuration属性来指定转换所用的时间。You can specify how long a transition takes by setting the GeneratedDuration property. 前面的示例有一个VisualState , 它指定按钮的边框在按下按钮时变得透明, 但如果快速按下并释放按钮, 动画的时间可能会很长。The preceding example has a VisualState that specifies that the button's border becomes transparent when the button is pressed, but the animation takes too long to be noticeable if the button is quickly pressed and released. 您可以使用VisualTransition来指定控件转换为按下状态所需的时间量。You can use a VisualTransition to specify the amount of time it takes the control to transition into the pressed state. 以下示例指定控件需要百分之一秒进入按下状态。The following example specifies that the control takes one hundredth of a second to go into the pressed state.

<!--Take one hundredth of a second to transition to the
    Pressed state.-->
<VisualTransition To="Pressed" 
                  GeneratedDuration="0:0:0.01" />

指定转换时控件外观发生的更改Specifying Changes to the Control's Appearance During a Transition

VisualTransition 包含在控件在状态之间Storyboard转换时开始的。The VisualTransition contains a Storyboard that begins when the control transitions between states. 例如,可以指定控件从 MouseOver 状态转换到 Normal 状态时发生的某个动画。For example, you can specify that a certain animation occurs when the control transitions from the MouseOver state to the Normal State. 下面的示例创建一个VisualTransition , 它指定当用户将鼠标指针从按钮上移开时, 按钮的边框将变为蓝色, 然后更改为黄色, 然后在1.5 秒内变为黑色。The following example creates a VisualTransition that specifies that when the user moves the mouse pointer away from the button, the button's border changes to blue, then to yellow, then to black in 1.5 seconds.

<!--Take one and a half seconds to transition from the
    MouseOver state to the Normal state. 
    Have the SolidColorBrush, BorderBrush, fade to blue, 
    then to yellow, and then to black in that time.-->
<VisualTransition From="MouseOver" To="Normal" 
                      GeneratedDuration="0:0:1.5">
  <Storyboard>
    <ColorAnimationUsingKeyFrames
      Storyboard.TargetProperty="Color"
      Storyboard.TargetName="BorderBrush"
      FillBehavior="HoldEnd" >

      <ColorAnimationUsingKeyFrames.KeyFrames>

        <LinearColorKeyFrame Value="Blue" 
          KeyTime="0:0:0.5" />
        <LinearColorKeyFrame Value="Yellow" 
          KeyTime="0:0:1" />
        <LinearColorKeyFrame Value="Black" 
          KeyTime="0:0:1.5" />

      </ColorAnimationUsingKeyFrames.KeyFrames>
    </ColorAnimationUsingKeyFrames>
  </Storyboard>
</VisualTransition>

指定何时应用 VisualTransitionSpecifying When a VisualTransition Is Applied

VisualTransition可以限制为仅应用于某些状态, 也可以在控件在状态之间转换时应用。A VisualTransition can be restricted to apply to only certain states, or it can be applied any time the control transitions between states. 在前面的示例中, VisualTransition当控件MouseOver从状态转换PressedNormal状态时应用VisualTransition ; 在该示例之前, 在控件进入状态时应用。In the preceding example, the VisualTransition is applied when the control goes from the MouseOver state to the Normal state; in the example before that, the VisualTransition is applied when the control goes into the Pressed state. 通过VisualTransition 设置和From属性来限制应用的时间。 ToYou restrict when a VisualTransition is applied by setting the To and From properties. 下表描述了从最严限制到最宽松限制的限制级别。The following table describes the levels of restriction from most restrictive to least restrictive.

限制类型Type of restriction 起始值Value of From 目标值Value of To
从一个指定状态到另一个指定状态From a specified state to another specified state 的名称VisualStateThe name of a VisualState 的名称VisualStateThe name of a VisualState
从任意状态到指定状态From any state to a specified state 未设置Not set 的名称VisualStateThe name of a VisualState
从指定状态到任意状态From a specified state to any state 的名称VisualStateThe name of a VisualState 未设置Not set
从任意状态到其他任意状态From any state to any other state 未设置Not set 未设置Not set

中可以有多VisualTransition个引用相同状态的对象,但它们将按照上表指定的顺序使用。VisualStateGroupYou can have multiple VisualTransition objects in a VisualStateGroup that refer to the same state, but they will be used in the order that the previous table specifies. 在下面的示例中, 有两VisualTransition个对象。In the following example, there are two VisualTransition objects. 当控件Pressed从状态转换VisualTransition MouseOver到状态时, 将使用同时From具有和To的。When the control transitions from the Pressed state to the MouseOver state, the VisualTransition that has both From and To set is used. 当控件从非 Pressed 的状态转换为 MouseOver 状态时,将使用另一种状态。When the control transitions from a state that is not Pressed to the MouseOver state, the other state is used.

<!--Take one half second to trasition to the MouseOver state.-->
<VisualTransition To="MouseOver" 
                  GeneratedDuration="0:0:0.5" />

<!--Take one hundredth of a second to transition from the
    Pressed state to the MouseOver state.-->
<VisualTransition From="Pressed" To="MouseOver" 
                  GeneratedDuration="0:0:0.01" />

VisualStateGroup VisualState VisualTransition具有一个Transitions属性, 该属性包含应用于中的对象的对象。 VisualStateGroupThe VisualStateGroup has a Transitions property that contains the VisualTransition objects that apply to the VisualState objects in the VisualStateGroup. 作为作者, 你可以随意包含所需的VisualTransition任何一个。 ControlTemplateAs the ControlTemplate author, you are free to include any VisualTransition you want. 但是, 如果To将和From属性设置为VisualTransition不在中VisualStateGroup的状态名称, 则将忽略。However, if the To and From properties are set to state names that are not in the VisualStateGroup, the VisualTransition is ignored.

下面的示例演示VisualStateGroup CommonStates的。The following example shows the VisualStateGroup for the CommonStates. 此示例为每VisualTransition个按钮的以下转换定义一个。The example defines a VisualTransition for each of the button's following transitions.

  • 转换为 Pressed 状态。To the Pressed state.

  • 转换为 MouseOver 状态。To the MouseOver state.

  • Pressed 状态转换为 MouseOver 状态。From the Pressed state to the MouseOver state.

  • MouseOver 状态转换为 Normal 状态。From the MouseOver state to the Normal state.

<VisualStateGroup x:Name="CommonStates">

  <!--Define the VisualTransitions that
      can be used when the control transitions 
      between VisualStates that are defined in the
      VisualStatGroup.-->
  <VisualStateGroup.Transitions>

    <!--Take one hundredth of a second to 
        transition to the Pressed state.-->
    <VisualTransition To="Pressed" 
                      GeneratedDuration="0:0:0.01" />

    <!--Take one half second to trasition 
        to the MouseOver state.-->
    <VisualTransition To="MouseOver" 
                      GeneratedDuration="0:0:0.5" />

    <!--Take one hundredth of a second to transition from the
        Pressed state to the MouseOver state.-->
    <VisualTransition From="Pressed" To="MouseOver" 
                      GeneratedDuration="0:0:0.01" />

    <!--Take one and a half seconds to transition from the
        MouseOver state to the Normal state. 
        Have the SolidColorBrush, BorderBrush, fade to blue, 
        then to yellow, and then to black in that time.-->
    <VisualTransition From="MouseOver" To="Normal" 
                      GeneratedDuration="0:0:1.5">
      <Storyboard>
        <ColorAnimationUsingKeyFrames
          Storyboard.TargetProperty="Color"
          Storyboard.TargetName="BorderBrush"
          FillBehavior="HoldEnd" >

          <ColorAnimationUsingKeyFrames.KeyFrames>
            <LinearColorKeyFrame Value="Blue" 
              KeyTime="0:0:0.5" />
            <LinearColorKeyFrame Value="Yellow" 
              KeyTime="0:0:1" />
            <LinearColorKeyFrame Value="Black" 
              KeyTime="0:0:1.5" />

          </ColorAnimationUsingKeyFrames.KeyFrames>
        </ColorAnimationUsingKeyFrames>
      </Storyboard>
    </VisualTransition>
  </VisualStateGroup.Transitions>

  <!--The remainder of the VisualStateGroup is the
      same as the previous example.-->

  <VisualState x:Name="Normal" />

  <VisualState x:Name="MouseOver">
    <Storyboard>
      <ColorAnimation 
        Storyboard.TargetName="BorderBrush" 
        Storyboard.TargetProperty="Color" 
        To="Red" />

    </Storyboard>
  </VisualState>

  <VisualState x:Name="Pressed">
    <Storyboard>
      <ColorAnimation 
        Storyboard.TargetName="BorderBrush" 
        Storyboard.TargetProperty="Color" 
        To="Transparent"/>
    </Storyboard>
  </VisualState>

  <!--The Disabled state is omitted for brevity.-->

</VisualStateGroup>

通过了解控件协定自定义其他控件Customizing Other Controls by Understanding the Control Contract

使用ControlTemplate来指定其视觉对象 (通过使用FrameworkElement对象) 和可视行为 (通过使用VisualState对象) 的控件使用 part 控件模型。A control that uses a ControlTemplate to specify its visual structure (by using FrameworkElement objects) and visual behavior (by using VisualState objects) uses the parts control model. WPFWPF 4 附带的许多控件均使用此模型。Many of the controls that are included with WPFWPF 4 use this model. ControlTemplate作者需要注意的部分是通过控制协定进行传递的。The parts that a ControlTemplate author needs to be aware of are communicated through the control contract. 了解控件协定的各个部件后,可以自定义使用部件控件模型的任意控件的外观。When you understand the parts of a control contract, you can customize the appearance of any control that uses the parts control model.

控件协定具有三个元素:A control contract has three elements:

  • 控件逻辑使用的可视元素。The visual elements that the control's logic uses.

  • 控件状态和每种状态所属的组。The states of the control and the group each state belongs to.

  • 以可视方式影响控件的公共属性。The public properties that visually affect the control.

控件协定中的可视元素Visual Elements in the Control Contract

有时FrameworkElement , 控件的逻辑与ControlTemplate中的相交互。Sometimes a control's logic interacts with a FrameworkElement that is in the ControlTemplate. 例如,控件可能会处理它的其中一个元素的事件。For example, the control might handle an event of one of its elements. 当控件需要FrameworkElement ControlTemplate在中查找特定的时, 它必须将该信息ControlTemplate传递给作者。When a control expects to find a particular FrameworkElement in the ControlTemplate, it must convey that information to the ControlTemplate author. 控件使用TemplatePartAttribute来传递所需的元素类型以及该元素的名称。The control uses the TemplatePartAttribute to convey the type of element that is expected, and what the name of the element should be. Button具有FrameworkElement其控件协定中的部分, 但其他ComboBox控件 (如) 执行。The Button does not have FrameworkElement parts in its control contract, but other controls, such as the ComboBox, do.

下面的示例演示TemplatePartAttributeComboBox类上指定的对象。The following example shows the TemplatePartAttribute objects that are specified on the ComboBox class. ComboBox逻辑应在其PART_Popup Popup TextBoxControlTemplate找到名PART_EditableTextBox为的和命名的。The logic of ComboBox expects to find a TextBox named PART_EditableTextBox and a Popup named PART_Popup in its ControlTemplate.

[TemplatePartAttribute(Name = "PART_EditableTextBox", Type = typeof(TextBox))]
[TemplatePartAttribute(Name = "PART_Popup", Type = typeof(Popup))]
public class ComboBox : ItemsControl
{
}
<TemplatePartAttribute(Name:="PART_EditableTextBox", Type:=GetType(TextBox))> _
<TemplatePartAttribute(Name:="Part_Popup", Type:=GetType(Popup))> _
Public Class ComboBox
    Inherits ItemsControl

End Class

下面的示例演示了的ControlTemplate简化ComboBox , 其中包括ComboBox类中的TemplatePartAttribute对象指定的元素。The following example shows a simplified ControlTemplate for the ComboBox that includes the elements that are specified by the TemplatePartAttribute objects on the ComboBox class.

<ControlTemplate TargetType="ComboBox">
  <Grid>
    <ToggleButton x:Name="DropDownToggle"
      HorizontalAlignment="Stretch" VerticalAlignment="Stretch"  
      Margin="-1" HorizontalContentAlignment="Right"
      IsChecked="{Binding Path=IsDropDownOpen,Mode=TwoWay,
                  RelativeSource={RelativeSource TemplatedParent}}">
      <Path x:Name="BtnArrow" Height="4" Width="8" 
        Stretch="Uniform" Margin="0,0,6,0"  Fill="Black"
        Data="F1 M 300,-190L 310,-190L 305,-183L 301,-190 Z " />
    </ToggleButton>
    <ContentPresenter x:Name="ContentPresenter" Margin="6,2,25,2"
      Content="{TemplateBinding SelectionBoxItem}"
      ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}"
      ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}">
    </ContentPresenter>
    <TextBox x:Name="PART_EditableTextBox"
      Style="{x:Null}"
      Focusable="False"
      Background="{TemplateBinding Background}"
      HorizontalAlignment="Left" 
      VerticalAlignment="Center" 
      Margin="3,3,23,3"
      Visibility="Hidden"
      IsReadOnly="{TemplateBinding IsReadOnly}"/>

    <Popup x:Name="PART_Popup"
      IsOpen="{TemplateBinding IsDropDownOpen}">
      <Border x:Name="PopupBorder" 
        HorizontalAlignment="Stretch" Height="Auto" 
        MinWidth="{TemplateBinding ActualWidth}"
        MaxHeight="{TemplateBinding MaxDropDownHeight}"
        BorderThickness="{TemplateBinding BorderThickness}" 
        BorderBrush="Black" Background="White" CornerRadius="3">
        <ScrollViewer x:Name="ScrollViewer" BorderThickness="0" Padding="1">
          <ItemsPresenter/>
        </ScrollViewer>
      </Border>
    </Popup>

  </Grid>
</ControlTemplate>

控件协定中的状态States in the Control Contract

控件状态也属于控件协定。The states of a control are also a part of the control contract. ControlTemplate为创建的示例Button演示如何根据其状态指定的外观。 ButtonThe example of creating a ControlTemplate for a Button shows how to specify the appearance of a Button depending on its states. 为每个VisualState指定的状态创建一个VisualStateGroup, 并VisualState将共享GroupName中的所有对象放入中, 如更改控件的外观 (具体取决于本主题前面部分的状态所述)。You create a VisualState for each specified state and put all VisualState objects that share a GroupName in a VisualStateGroup, as described in Changing the Appearance of a Control Depending on Its State earlier in this topic. 第三方控件应使用TemplateVisualStateAttribute来指定状态, 这使设计器工具 (如 Expression Blend) 能够公开控件的状态以创作控件模板。Third-party controls should specify states by using the TemplateVisualStateAttribute, which enables designer tools, such as Expression Blend, to expose the control's states for authoring control templates.

若要查找 WPFWPF 中随附的控件的控件协定,请参阅 Control 样式和模板To find the control contract for controls that are included with WPFWPF, see Control Styles and Templates.

控件协定中的属性Properties in the Control Contract

以可视方式影响控件的公共属性也包含在控件协定中。The public properties that visually affect the control are also included in the control contract. 可以设置这些属性来更改控件的外观, 而无需创建新ControlTemplate的。You can set these properties to change the appearance of the control without creating a new ControlTemplate. 还可以使用TemplateBinding标记扩展将中ControlTemplate元素的属性绑定到由Button定义的公共属性。You can also use the TemplateBinding markup extension to bind properties of elements that are in the ControlTemplate to public properties that are defined by the Button.

以下示例展示了按钮的控件协定。The following example shows the control contract for the button.

[TemplateVisualState(Name = "Normal", GroupName = "CommonStates")]
[TemplateVisualState(Name = "MouseOver", GroupName = "CommonStates")]
[TemplateVisualState(Name = "Pressed", GroupName = "CommonStates")]
[TemplateVisualState(Name = "Disabled", GroupName = "CommonStates")]
[TemplateVisualState(Name = "Unfocused", GroupName = "FocusStates")]
[TemplateVisualState(Name = "Focused", GroupName = "FocusStates")]
public class Button : ButtonBase
{
    public static readonly DependencyProperty BackgroundProperty;
    public static readonly DependencyProperty BorderBrushProperty;
    public static readonly DependencyProperty BorderThicknessProperty;
    public static readonly DependencyProperty ContentProperty;
    public static readonly DependencyProperty ContentTemplateProperty;
    public static readonly DependencyProperty FontFamilyProperty;
    public static readonly DependencyProperty FontSizeProperty;
    public static readonly DependencyProperty FontStretchProperty;
    public static readonly DependencyProperty FontStyleProperty;
    public static readonly DependencyProperty FontWeightProperty;
    public static readonly DependencyProperty ForegroundProperty;
    public static readonly DependencyProperty HorizontalContentAlignmentProperty;
    public static readonly DependencyProperty PaddingProperty;
    public static readonly DependencyProperty TextAlignmentProperty;
    public static readonly DependencyProperty TextDecorationsProperty;
    public static readonly DependencyProperty TextWrappingProperty;
    public static readonly DependencyProperty VerticalContentAlignmentProperty;

    public Brush Background { get; set; }
    public Brush BorderBrush { get; set; }
    public Thickness BorderThickness { get; set; }
    public object Content { get; set; }
    public DataTemplate ContentTemplate { get; set; }
    public FontFamily FontFamily { get; set; }
    public double FontSize { get; set; }
    public FontStretch FontStretch { get; set; }
    public FontStyle FontStyle { get; set; }
    public FontWeight FontWeight { get; set; }
    public Brush Foreground { get; set; }
    public HorizontalAlignment HorizontalContentAlignment { get; set; }
    public Thickness Padding { get; set; }
    public TextAlignment TextAlignment { get; set; }
    public TextDecorationCollection TextDecorations { get; set; }
    public TextWrapping TextWrapping { get; set; }
    public VerticalAlignment VerticalContentAlignment { get; set; }
}
<TemplateVisualState(Name:="Normal", GroupName:="CommonStates")> _
<TemplateVisualState(Name:="MouseOver", GroupName:="CommonStates")> _
<TemplateVisualState(Name:="Pressed", GroupName:="CommonStates")> _
<TemplateVisualState(Name:="Disabled", GroupName:="CommonStates")> _
<TemplateVisualState(Name:="Unfocused", GroupName:="FocusStates")> _
<TemplateVisualState(Name:="Focused", GroupName:="FocusStates")> _
Public Class Button
    Inherits ButtonBase

    Public Shared ReadOnly BackgroundProperty As DependencyProperty
    Public Shared ReadOnly BorderBrushProperty As DependencyProperty
    Public Shared ReadOnly BorderThicknessProperty As DependencyProperty
    Public Shared ReadOnly ContentProperty As DependencyProperty
    Public Shared ReadOnly ContentTemplateProperty As DependencyProperty
    Public Shared ReadOnly FontFamilyProperty As DependencyProperty
    Public Shared ReadOnly FontSizeProperty As DependencyProperty
    Public Shared ReadOnly FontStretchProperty As DependencyProperty
    Public Shared ReadOnly FontStyleProperty As DependencyProperty
    Public Shared ReadOnly FontWeightProperty As DependencyProperty
    Public Shared ReadOnly ForegroundProperty As DependencyProperty
    Public Shared ReadOnly HorizontalContentAlignmentProperty As DependencyProperty
    Public Shared ReadOnly PaddingProperty As DependencyProperty
    Public Shared ReadOnly TextAlignmentProperty As DependencyProperty
    Public Shared ReadOnly TextDecorationsProperty As DependencyProperty
    Public Shared ReadOnly TextWrappingProperty As DependencyProperty
    Public Shared ReadOnly VerticalContentAlignmentProperty As DependencyProperty

    Public Background As Brush
    Public BorderBrush As Brush
    Public BorderThickness As Thickness
    Public Content As Object
    Public ContentTemplate As DataTemplate
    Public FontFamily As FontFamily
    Public FontSize As Double
    Public FontStretch As FontStretch
    Public FontStyle As FontStyle
    Public FontWeight As FontWeight
    Public Foreground As Brush
    Public HorizontalContentAlignment As HorizontalAlignment
    Public Padding As Thickness
    Public TextAlignment As TextAlignment
    Public TextDecorations As TextDecorationCollection
    Public TextWrapping As TextWrapping
    Public VerticalContentAlignment As VerticalAlignment
End Class

创建ControlTemplate时, 通常最简单的方法是从现有ControlTemplate的开始, 对其进行更改。When creating a ControlTemplate, it is often easiest to begin with an existing ControlTemplate and make changes to it. 可以执行以下操作之一来更改现有ControlTemplate的:You can do one of the following to change an existing ControlTemplate:

完整的示例Complete Example

下面的示例演示本主题Button中讨论的完整ControlTemplateThe following example shows the complete ButtonControlTemplate that is discussed in this topic.

<StackPanel>
  <StackPanel.Resources>
    <Style TargetType="Button" x:Key="newTemplate">
      <!--Set the Background, Foreground, FontSize, Width, 
                  Height, Margin, and Template properties for
                  the Button.-->
      <Setter Property="Background" Value="Navy"/>
      <Setter Property="Foreground" Value="White"/>
      <Setter Property="FontSize" Value="14"/>
      <Setter Property="Width" Value="100"/>
      <Setter Property="Height" Value="40"/>
      <Setter Property="Margin" Value="10"/>
      <Setter Property="HorizontalContentAlignment" Value="Center"/>
      <Setter Property="VerticalContentAlignment" Value="Center"/>
      <Setter Property="Template">
        <Setter.Value>
          <ControlTemplate TargetType="Button">
            <Border x:Name="RootElement">
              <VisualStateManager.VisualStateGroups>

                <!--Define the states and transitions for the common states.
                    The states in the VisualStateGroup are mutually exclusive to
                    each other.-->
                <VisualStateGroup Name="CommonStates">

                  <!--Define the VisualTransitions that can be used when the control
                      transitions between VisualStates that are defined in the
                      VisualStatGroup.-->
                  <VisualStateGroup.Transitions>

                    <!--Take one hundredth of a second to transition to the
                        Pressed state.-->
                    <VisualTransition To="Pressed" 
                                      GeneratedDuration="0:0:0.01" />

                    <!--Take one half second to trasition to the MouseOver state.-->
                    <VisualTransition To="MouseOver" 
                                      GeneratedDuration="0:0:0.5" />

                    <!--Take one hundredth of a second to transition from the
                        Pressed state to the MouseOver state.-->
                    <VisualTransition From="Pressed" To="MouseOver" 
                                      GeneratedDuration="0:0:0.01" />

                    <!--Take one and a half seconds to transition from the
                        MouseOver state to the Normal state. 
                        Have the SolidColorBrush, BorderBrush, fade to blue, 
                        then to yellow, and then to black in that time.-->
                    <VisualTransition From="MouseOver" To="Normal" 
                                          GeneratedDuration="0:0:1.5">
                      <Storyboard>
                        <ColorAnimationUsingKeyFrames
                          Storyboard.TargetProperty="Color"
                          Storyboard.TargetName="BorderBrush"
                          FillBehavior="HoldEnd" >

                          <ColorAnimationUsingKeyFrames.KeyFrames>

                            <LinearColorKeyFrame Value="Blue" 
                              KeyTime="0:0:0.5" />
                            <LinearColorKeyFrame Value="Yellow" 
                              KeyTime="0:0:1" />
                            <LinearColorKeyFrame Value="Black" 
                              KeyTime="0:0:1.5" />

                          </ColorAnimationUsingKeyFrames.KeyFrames>
                        </ColorAnimationUsingKeyFrames>
                      </Storyboard>
                    </VisualTransition>
                  </VisualStateGroup.Transitions>

                  <!--The Normal state is the state the button is in
                      when it is not in another state from this VisualStateGroup.
                      There is no special visual behavior for this state, but
                      the VisualState must be defined in order for the button
                      to return to its initial state.-->
                  <VisualState x:Name="Normal" />

                  <!--Change the border of the button to red when the
                      mouse is over the button.-->
                  <VisualState x:Name="MouseOver">
                    <Storyboard>
                      <ColorAnimation Storyboard.TargetName="BorderBrush"     
                                      Storyboard.TargetProperty="Color"
                                      To="Red" />

                    </Storyboard>
                  </VisualState>

                  <!--Change the border of the button to Transparent when the
                      button is pressed.-->
                  <VisualState x:Name="Pressed">
                    <Storyboard >
                      <ColorAnimation Storyboard.TargetName="BorderBrush" 
                                      Storyboard.TargetProperty="Color" 
                                      To="Transparent" 
                                      />
                    </Storyboard>
                  </VisualState>

                  <!--Show the DisabledRect when the IsEnabled property on
                      the button is false.-->
                  <VisualState x:Name="Disabled">
                    <Storyboard>
                      <DoubleAnimation Storyboard.TargetName="DisabledRect" 
                                       Storyboard.TargetProperty="Opacity"
                                       To="1" Duration="0" />
                    </Storyboard>
                  </VisualState>
                </VisualStateGroup>

                <!--Define the states and transitions for the focus states.
                    The states in the VisualStateGroup are mutually exclusive to
                    each other.-->
                <VisualStateGroup x:Name="FocusStates">

                  <!--Define the VisualStates in this VistualStateGroup.-->
                  <VisualState x:Name="Focused">
                    <Storyboard>
                      <ObjectAnimationUsingKeyFrames 
                        Storyboard.TargetName="FocusVisual" 
                        Storyboard.TargetProperty="Visibility" Duration
                        ="0">
                        
                        <DiscreteObjectKeyFrame KeyTime="0">
                          <DiscreteObjectKeyFrame.Value>
                            <Visibility>Visible</Visibility>
                          </DiscreteObjectKeyFrame.Value>
                        </DiscreteObjectKeyFrame>
                      </ObjectAnimationUsingKeyFrames>
                    </Storyboard>
                  </VisualState>
                  <VisualState x:Name="Unfocused">
                    <Storyboard>
                      <ObjectAnimationUsingKeyFrames 
                        Storyboard.TargetName="FocusVisual" 
                        Storyboard.TargetProperty="Visibility"
                        Duration="0">
                        
                        <DiscreteObjectKeyFrame KeyTime="0">
                          <DiscreteObjectKeyFrame.Value>
                            <Visibility>Collapsed</Visibility>
                          </DiscreteObjectKeyFrame.Value>
                        </DiscreteObjectKeyFrame>
                      </ObjectAnimationUsingKeyFrames>
                    </Storyboard>
                  </VisualState>
                </VisualStateGroup>
              </VisualStateManager.VisualStateGroups>

              <!--Create the SolidColorBrush for the Background 
                  as an object elemment and give it a name so 
                  it can be referred to elsewhere in the control template.-->
              <Border.Background>
                <SolidColorBrush x:Name="BorderBrush" Color="Black"/>
              </Border.Background>

              <!--Create a border that has a different color by adding smaller grid.
                  The background of this grid is specified by the button's Background
                  property.-->
              <Grid Background="{TemplateBinding Background}" Margin="4">

                <!--Create a Rectangle that indicates that the
                    Button has focus.-->
                <Rectangle Name="FocusVisual" 
                           Visibility="Collapsed" Margin="2" 
                           Stroke="{TemplateBinding Foreground}" 
                           StrokeThickness="1" 
                           StrokeDashArray="1.5 1.5"/>

                <!--Use a ContentPresenter to display the Content of
                    the Button.-->
                <ContentPresenter
                  HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                  VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                  Margin="4,5,4,4" />

                <!--Create a rectangle that causes the button to appear
                    grayed out when it is disabled.-->
                <Rectangle x:Name="DisabledRect" 
                         Fill="#A5FFFFFF"
                         Opacity="0" IsHitTestVisible="false" />
              </Grid>
            </Border>
          </ControlTemplate>
        </Setter.Value>
      </Setter>
    </Style>

  </StackPanel.Resources>

  <Button Style="{StaticResource newTemplate}" 
          Content="Button1"/>

  <Button Style="{StaticResource newTemplate}"
          Background="Purple" 
          Content="Button2" />
</StackPanel>

请参阅See also