建立控制項的範本Create a template for a control
使用 Windows Presentation Foundation (WPF) ,您可以使用自己可重複使用的範本自訂現有控制項的視覺化結構和行為。With Windows Presentation Foundation (WPF), you can customize an existing control's visual structure and behavior with your own reusable template. 範本可全域套用至您的應用程式、windows 和頁面,或直接套用至控制項。Templates can be applied globally to your application, windows and pages, or directly to controls. 您可以改為建立現有控制項的新範本,以涵蓋需要您建立新控制項的大部分案例。Most scenarios that require you to create a new control can be covered by instead creating a new template for an existing control.
重要
.NET 5 (和 .NET Core) 的桌面指南檔正在結構中。The Desktop Guide documentation for .NET 5 (and .NET Core) is under construction.
在本文中,您將探索如何為控制項建立新的 ControlTemplate Button 。In this article, you'll explore creating a new ControlTemplate for the Button control.
建立 ControlTemplate 的時機When to create a ControlTemplate
控制項有許多屬性,例如 Background 、 Foreground 和 FontFamily 。Controls have many properties, such as Background, Foreground, and FontFamily. 這些屬性會控制控制面板的不同層面,但您可以藉由設定這些屬性進行的變更會受到限制。These properties control different aspects of the control's appearance, but the changes that you can make by setting these properties are limited. 例如,您可以將屬性設定 Foreground 為 [藍色],並將設定 FontStyle 為 [斜體] CheckBox 。For example, you can set the Foreground property to blue and FontStyle to italic on a CheckBox. 如果您想要自訂控制項的外觀,而不是控制項上其他屬性所能做的設定,您可以建立 ControlTemplate 。When you want to customize the control's appearance beyond what setting the other properties on the control can do, you create a ControlTemplate.
在大部分的使用者介面中,按鈕具有相同的一般外觀:有一些文字的矩形。In most user interfaces, a button has the same general appearance: a rectangle with some text. 如果您想要建立圓角按鈕,您可以建立繼承自按鈕的新控制項,或重新建立按鈕的功能。If you wanted to create a rounded button, you could create a new control that inherits from the button or recreates the functionality of the button. 此外,新的使用者控制項會提供圓形視覺效果。In addition, the new user control would provide the circular visual.
您可以自訂現有控制項的視覺化配置,以避免建立新的控制項。You can avoid creating new controls by customizing the visual layout of an existing control. 使用圓角按鈕時,您可以 ControlTemplate 使用所需的視覺版面配置來建立。With a rounded button, you create a ControlTemplate with the desired visual layout.
另一方面,如果您需要的控制項有新功能、不同的屬性和新的設定,您可以建立新的 UserControl 。On the other hand, if you need a control with new functionality, different properties, and new settings, you would create a new UserControl.
必要條件Prerequisites
建立新的 WPF 應用程式,並在 MainWindow 中 (或您選擇的另一個視窗) 在 : :: no loc (
Title | Template Intro Sample |
SizeToContent | WidthAndHeight |
MinWidth | 250 |
將 : ::非 loc (
<StackPanel Margin="10">
<Label>Unstyled Button</Label>
<Button>Button 1</Button>
<Label>Rounded Button</Label>
<Button>Button 2</Button>
</StackPanel>
最後, MainWindow .xaml 檔案看起來應該會如下所示:In the end, the MainWindow.xaml file should look similar to the following:
<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>
如果您執行應用程式,它看起來如下所示:If you run the application, it looks like the following:
建立 ControlTemplateCreate a ControlTemplate
最常見的宣告方式是在 ControlTemplate XAML 檔案中的區段中做為資源 Resources
。The most common way to declare a ControlTemplate is as a resource in the Resources
section in a XAML file. 因為範本是資源,所以它們會遵守適用于所有資源的相同範圍規則。Because templates are resources, they obey the same scoping rules that apply to all resources. 單純地說,您宣告範本的位置會影響可以套用範本的位置。Put simply, where you declare a template affects where the template can be applied. 例如,如果您在應用程式定義 XAML 檔案的根項目中宣告範本,則範本可以在應用程式中的任何位置使用。For example, if you declare the template in the root element of your application definition XAML file, the template can be used anywhere in your application. 如果您在視窗中定義範本,則只有該視窗中的控制項可以使用該範本。If you define the template in a window, only the controls in that window can use the template.
若要開始,請將專案新增 Window.Resources
至您的 MainWindow .xaml 檔案:To start with, add a Window.Resources
element to your MainWindow.xaml file:
<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>
建立新的 : ::非 loc (
x:Keyx:Key | roundbutton |
TargetType | Button |
此控制項範本將很簡單:This control template will be simple:
- 控制項的根項目,a Grida root element for the control, a Grid
- Ellipse,用來繪製按鈕的圓角外觀an Ellipse to draw the rounded appearance of the button
- ContentPresenter,顯示使用者指定的按鈕內容a ContentPresenter to display the user-specified button content
<ControlTemplate x:Key="roundbutton" TargetType="Button">
<Grid>
<Ellipse Fill="{TemplateBinding Background}" Stroke="{TemplateBinding Foreground}" />
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
</Grid>
</ControlTemplate>
TemplateBindingTemplateBinding
當您建立新的時 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 a 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.
橢圓形Ellipse
請注意 Fill :: Stroke : no loc (
ContentPresenterContentPresenter
您也會將 : ::非 loc (
<Button>My Text</Button>
<!-- and -->
<Button>
<CheckBox>Checkbox in a button</CheckBox>
</Button>
在上述兩個範例中,文字和核取方塊都會設定為 [ 內容 ] 屬性。In both of the previous examples, the text and the checkbox are set as the Button.Content property. 無論內容為何,都可以透過 : ::非 loc (
如果套用 ControlTemplate 至 ContentControl 類型(例如 Button
),則 ContentPresenter 會在元素樹狀結構中搜尋。If the ControlTemplate is applied to a ContentControl type, such as a Button
, a ContentPresenter is searched for in the element tree. 如果 ContentPresenter
找到,則範本會自動將控制項的屬性系結 Content 至 ContentPresenter
。If the ContentPresenter
is found, the template automatically binds the control's Content property to the ContentPresenter
.
使用範本Use the template
尋找在本文一開始所宣告的按鈕。Find the buttons that were declared at the start of this article.
<StackPanel Margin="10">
<Label>Unstyled Button</Label>
<Button>Button 1</Button>
<Label>Rounded Button</Label>
<Button>Button 2</Button>
</StackPanel>
將第二個按鈕的 Template 屬性設為 roundbutton
資源:Set the second button's Template property to the roundbutton
resource:
<StackPanel Margin="10">
<Label>Unstyled Button</Label>
<Button>Button 1</Button>
<Label>Rounded Button</Label>
<Button Template="{StaticResource roundbutton}">Button 2</Button>
</StackPanel>
如果您執行專案並查看結果,您會看到按鈕具有圓角背景。If you run the project and look at the result, you'll see that the button has a rounded background.
您可能已經注意到按鈕不是圓形,但卻扭曲。You may have noticed that the button isn't a circle but is skewed. 由於 : :: no loc (
<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>
新增觸發程式Add a Trigger
雖然套用範本的按鈕看起來不同,但它的行為與任何其他按鈕的行為相同。Even though a button with a template applied looks different, it behaves the same as any other button. 如果您按下按鈕,就會 Click 引發事件。If you press the button, the Click event fires. 不過,您可能已經注意到,當您將滑鼠移至按鈕上方時,按鈕的視覺效果不會變更。However, you may have noticed that when you move your mouse over the button, the button's visuals don't change. 這些視覺效果互動全都由範本所定義。These visual interactions are all defined by the template.
使用 WPF 提供的動態事件和屬性系統,您可以監看某個值的特定屬性,然後在適當的情況下重新造型範本。With the dynamic event and property systems that WPF provides, you can watch a specific property for a value and then restyle the template when appropriate. 在此範例中,您將監看按鈕的 IsMouseOver 屬性。In this example, you'll watch the button's IsMouseOver property. 當滑鼠停留在控制項上時,使用新的色彩來將 : :: no loc (
若要這樣做,您必須將名稱新增至您可以參考的 : :: no loc (
<Ellipse x:Name="backgroundElement" Fill="{TemplateBinding Background}" Stroke="{TemplateBinding Foreground}" />
接下來,將新的新增 Trigger 至 ControlTemplate 集合。Next, add a new Trigger to the ControlTemplate.Triggers collection. 觸發程式會監看 IsMouseOver
值的事件 true
。The trigger will watch the IsMouseOver
event for the value 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>
接下來,將 : ::非 loc (
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Fill" TargetName="backgroundElement" Value="AliceBlue"/>
</Trigger>
執行專案。Run the project. 請注意,當您將滑鼠移至按鈕上方時,:: : no loc (
使用 VisualStateUse a VisualState
視覺狀態是由控制項所定義和觸發。Visual states are defined and triggered by a control. 例如,當滑鼠移到控制項上方時, CommonStates.MouseOver
就會觸發狀態。For example, when the mouse is moved on top of the control, the CommonStates.MouseOver
state is triggered. 您可以根據控制項目前的狀態,建立屬性變更的動畫。You can animate property changes based on the current state of the control. 在上一節中,已使用 : :: no loc (AliceBlue
當屬性為時 IsMouseOver
true
。In the previous section, a <PropertyTrigger> was used to change the foreground of the button to AliceBlue
when the IsMouseOver
property was true
. 相反地,請建立以動畫顯示此色彩變更的視覺狀態,以提供順暢的轉換。Instead, create a visual state that animates the change of this color, providing a smooth transition. 如需 VisualStates 的詳細資訊,請參閱 WPF 中的樣式和範本。For more information about VisualStates, see Styles and templates in WPF.
若要將 : :: no loc (
<ControlTemplate x:Key="roundbutton" TargetType="Button">
<Grid>
<Ellipse x:Name="backgroundElement" Fill="{TemplateBinding Background}" Stroke="{TemplateBinding Foreground}" />
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
</Grid>
</ControlTemplate>
接下來,在控制項範本的 : :: no loc (CommonStates
。Next, in the <Grid> root of the control template, add the <VisualStateManager.VisualStateGroups> element with a <VisualStateGroup> for CommonStates
. 定義兩個狀態: Normal
和 MouseOver
。Define two states, Normal
and 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>
當觸發該狀態時,會套用在 : ::非 loc (
正常Normal
此狀態會將橢圓形填滿,並將其還原為控制項的
Background
色彩。This state animates the ellipse fill, restoring it to the control'sBackground
color.<Storyboard> <ColorAnimation Storyboard.TargetName="backgroundElement" Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)" To="{TemplateBinding Background}" Duration="0:0:0.3"/> </Storyboard>
MouseOverMouseOver
這個狀態會將橢圓形
Background
色彩繪製成新的色彩:Yellow
。This state animates the ellipseBackground
color to a new color:Yellow
.<Storyboard> <ColorAnimation Storyboard.TargetName="backgroundElement" Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)" To="Yellow" Duration="0:0:0.3"/> </Storyboard>
: ::非 loc (
<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>
執行專案。Run the project. 請注意,當您將滑鼠移至按鈕上方時,:: : no loc (