Windows Phone 7 - 淺談Custom Control
最近在開發一些應用,想要對現有的控件進行客製,不想透過程式化硬寫出一個Control出來,
而且好奇對於控件的Style與ContentTemplate怎麼透過XAML就可以定義一個新控件的樣式,
希望透過該篇可以加以了解怎麼自訂一個控件。
要自訂控件,要先了解XAML提供何種方式讓設計人員可以調整現有的控件為新型的控件?
〉Using Styles to Change the Appearance of Multiple Controls:
修改控件的外貌有二種方式:
‧Styles:定義控件屬性設定的集合。方便簡單的地修改控件的既有屬性;
‧Templates:一份XAML定義控件的Visual appearance與Visual behavior,取代控件的外貌,呈現完全不同的控件。
(A) Styles:
Styles基本上是目標屬性設定的集合,透過指定的控件目標(TargetType)做為適用的類型,讓控件可透過Style屬性設定,
轉換成定義好的Styles。(需注意控件指定Style時,在XAML模式下需符合StaticResource Markup Extension的格式),如下:
1:
2: <StackPanel.Resources>
3: <Style TargetType="Button" x:Key="myButtonStyle">
4: <Setter Property="Background" Value="Purple" />
5: <Setter Property="Foreground" Value="#9900FF" />
6: <Setter Property="Height" Value="50" />
7: <Setter Property="Width" Value="100" />
8: <Setter Property="Margin" Value="5" />
9: <Setter Property="HorizontalContentAlignment" Value="Center" />
10: <Setter Property="VerticalContentAlignment" Value="Center" />
11: <Setter Property="Cursor" Value="Hand" />
12: <Setter Property="FontSize" Value="14" />
13: </Style>
14: </StackPanel.Resources>
15:
16:
17: ...
18:
19:
20: <Button x:Name="button3" Width="130" Content="Click Me Instead!" Style="{StaticResource myButtonStyle}"/>
(B). ContentTemplate:
ContentTemplate可用於定義控件的Visual structure與Visual behavior,所以透過它可自訂Control呈現的樣式,
但需注意只支援定義外貌,無法修改它的功能。透過<ControlTemplate Class>定義Button例子加以說明:
1:
2: <ControlTemplate TargetType="Button">
3: <Grid >
4: <VisualStateManager.VisualStateGroups>
5: <VisualStateGroup x:Name="CommonStates">
6:
7: <VisualStateGroup.Transitions>
8:
9: <!--Take one half second to trasition to the MouseOver state.-->
10: <VisualTransition To="MouseOver"
11: GeneratedDuration="0:0:0.5"/>
12: </VisualStateGroup.Transitions>
13:
14: <VisualState x:Name="Normal" />
15:
16: <!--Change the SolidColorBrush, ButtonBrush, to red when the
17: mouse is over the button.-->
18: <VisualState x:Name="MouseOver">
19: <Storyboard>
20: <ColorAnimation Storyboard.TargetName="ButtonBrush"
21: Storyboard.TargetProperty="Color" To="Red" />
22: </Storyboard>
23: </VisualState>
24: </VisualStateGroup>
25: </VisualStateManager.VisualStateGroups>
26: <Grid.Background>
27: <SolidColorBrush x:Name="ButtonBrush" Color="Green"/>
28: </Grid.Background>
29: </Grid>
30: </ControlTemplate>
Button使用Grid加以包裝,並且VisualStateManager定義在各種VisualState下要執行的任務,更搭配VisualStateGroup.Transactions
定義要執行的轉換項目,最後配合Storyboard定義顏色轉換的效果。
那麼ContentTemplate在使用上到底有那些重點呢?
B-1. Control Contract:
Control Contract強調客製Control必須嚴格的分隔:logic與visuals。這樣的好處在於讓二者不會互相牽扯,降低它們的耦合,
Designer可專心設計需要控件與具有的子項目,開發人員專心寫控件與子項目的功能,共同完成控件的功能。
然而,Control Contract內容包括:
‧Visual properties exposed on the control class.
‧Expected parts in the template.
‧Expected logic associated with the parts in the template.
B-2. Parts and States Model:
Silverlight中經由Parts and States Model實作Control Contract,該Model保持分割logic與visual的理念,主要由:
Parts、States、State Groups與Visual Transitions所構成。要怎麼知道Control具有的Parts and States Model為何呢?
可參考<Control Styles and Templates>從中得知客製控件時,要怎麼使用其中的內容。
以下擷錄<Control Customization>說明Parts、States、States Groups與Visual Transitions:
1. Parts:
在ContentTemplate中Parts被稱為Element,因此,logic處理部分主要是針對這些Element進行操作。以下是介紹ComboBox控件
的組合結構,主要分成五個部分:ContentPresenter、ContentPresenterBorder、DropDownToggle、ScrollViewer、Popup。
2. States與State Groups:
Visual State用於識別目前控件出現的狀態類型,舉例來說:下圖即說明Button的三種狀態中Background Color的改變。
State Groups本身是一組互斥狀態的集合,不同的狀態組也有可能是正相交的。這也代表,控件可能同一時間具有二種
不同的States,並且它們來自不同的State Groups。以下舉Combox為例,它具有四種State Groups:ComonStates、CheckStates、
FocusSates、ValidationStates。
Combox可以同一時間出現Normal與Checked二種States,因為它各來自不同的State Groups。但不可以Normal與Pressed同時,
因為它們屬於同一個State Groups。
3. Visual Transitions:
用於呈現控件視覺化由一個狀態轉換成另一個狀態的結果,透過下圖的例子更容易明白,Button的狀態改成Background也跟著
改變,這一連串的視覺變化就是:Visual Transitions。
以上是針對ContentTemplate的定義加以說明,如果想知道更詳細怎麼使用ContentTemplate建立一個新控件,可以參考:
<Creating a New Control by Creating a ControlTemplate>有更多的範例說明。
以上是針對Styles與ContentTemplate的概要說明,接下來便實際來做看看怎麼客製一個新的Control吧。
(C) 實作範例:
1. How to Define the ContentTemplate in XAML:
透過Template屬性來定義控件的ContentTemplate,以下為MSDN上指出可定義Template的方式,如下:
‧Locally set Template to a ControlTemplate that is defined inline;
1: <!-- Locally set Template to a ControlTemplate that is defined inline. -->
2: <Button Content="Button1">
3: <Button.Template>
4: <ControlTemplate TargetType="Button">
5:
6: <!--Define the ControlTemplate here.-->
7:
8: </ControlTemplate>
9: </Button.Template>
10: </Button>
‧Locally set Template to a reference to a ControlTemplate that is defined as a resource;
1: <!-- Locally set Template to a reference to a ControlTemplate that is defined as a resource. -->
2: <StackPanel>
3: <StackPanel.Resources>
4: <ControlTemplate TargetType="Button" x:Key="newTemplate">
5:
6: <!--Define the ControlTemplate here.-->
7:
8: </ControlTemplate>
9: </StackPanel.Resources>
10:
11: <Button Template="{StaticResource newTemplate}" Content="Button1"/>
12: </StackPanel>
‧Set Template and define a ControlTemplate in a Style;
1: <!-- Set Template and define a ControlTemplate in a Style. -->
2: <StackPanel>
3: <StackPanel.Resources>
4: <Style TargetType="Button" x:Key="newTemplate">
5: <Setter Property="Template">
6: <Setter.Value>
7: <ControlTemplate TargetType="Button">
8:
9: <!--Define the ControlTemplate here.-->
10:
11: </ControlTemplate>
12: </Setter.Value>
13: </Setter>
14: </Style>
15: </StackPanel.Resources>
16: <Button Style="{StaticResource newTemplate}" Content="Button1"/>
17: </StackPanel>
以上三種均是可以定義ContentTemplate的方式,看自行的需要來使用,但使用的範圍可以根據上層包裝的父標籤有所不同。
2. Changing the Visual Structure of a Control:
在Silverlight中每一個控件通常是FrameworkElement objects組合而成的,當使用ContentTemplate定義控件的新樣式時,
ContentTemplate只能有一個FrameworkElement為「Root Element」,也就代表ContentTemplate需要一個控件來包裝其他控件。
組合的結果即為Visual Structure。以下舉例Button控件在ContentTemplate被修改的樣式:
1: <Button Width="100" Height="100"
2: x:Name="btnData" Content="測試" Background="Red">
3: <Button.Template>
4: <ControlTemplate TargetType="Button" x:Name="newTemplate">
5: <Border x:Name="RootElement" >
6: <!--為Border建立SolidColorBrush物件,並且給予一個名稱,
7: 它可在這Template中被使用-->
8: <Border.Background>
9: <SolidColorBrush x:Name="BorderBrush" Color="White"/>
10: </Border.Background>
11:
12: <!--為Grid建立不同的Background,分開與Border背景不同的顏色,Grid的Background,
13: 代表Button的Background顏色-->
14: <Grid Margin="4" x:Name="GridBrush" Background="{TemplateBinding Background}">
15:
16: <!--使用ContentPresenter呈現Button的Content-->
17: <ContentPresenter
18: HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
19: VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
20: Margin="0,0,0,0" />
21:
22: </Grid>
23: </Border>
24: </ControlTemplate>
25: </Button.Template>
26: </Button>
在上述的範例裡出現了一個重要關鍵字「TemplateBinding」,它的功能為何?
如果使用ContentTemplate時想要延用既有控件的公開屬性,TemplateBinding是標準的作法協助取得這些屬性。
以上述範例來看,ContentTemplate在Background使用了TemplateBinding,如此一來,在原有Button上設定Background,
相同的Grid也會被影響,BorderBrush也是相同的道理。
Control class 定義了一些屬性可被用於ContentTemplated影響Visual Structures裡的控件。至於ContentTemplate怎麼
使用相依的屬性呢?主要有二個方式:
(1) 在ContentTemplate中的Element使用Binding到該屬性;
(2) 在ContentTemplate中的Element繼承來從FrameworkElement的屬性;
下列擷取MSDN中提供的可視屬性表:
| Property | Usage method |
| Background | Template binding |
| BorderThickness | Template binding |
| BorderBrush | Template binding |
| FontFamily | Property inheritance or Template binding |
| FontSizd | Property inheritance or Template binding |
| ForStretch | 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類別,更包括:DataContext、Language、TextDecordation等來自FrameworkElement屬性,
比較特別的是:ContentPresenter與ItemPresenter分成在ContentControl與ItemsControl裡的ContentTemplate自動binding。
那麼定義好的ContentTemplate要怎麼套用於新的Button呢?如下:
1: <StackPanel>
2: <!-- 透過StatisResource指定剛定義好的ContentTemplate -->
3: <Button Style="{StaticResource newTemplate}"
4: Background="Navy" Foreground="White" FontSize="14"
5: Content="Button1"/>
6:
7: <Button Style="{StaticResource newTemplate}"
8: Background="Purple" Foreground="White" FontSize="14"
9: Content="Button2" Click="Button_Click"/>
10: </StackPanel>
3. Changing the Appearance of a Control Depending on Its State:
了解如何定義ContentTemplate、調整Visual Structures後,接下來即是了解如何透過State與State Groups的改變,影響控件本身。
ContentTemplate不能改變Control的功能,卻可改變Visual Behavior(視覺行為)。Visual Behavior描述控件在一定狀態下的顯示外觀。
舉Button的例子來說,Click事件是功能,但Button在Click有多種Visual Behavior(滑入、按下、放開)它們均影響著Button的外觀。
在ContentTemplate中利用VisualState指定控件在一定狀態下出現的樣式,並且它更可結合Storyboard讓外觀更有效果。
另外,在控件State的邏輯可直接使用VisualStateManager控件Control本身具有的VisualState。以下舉例指定VisualState.Name啟動
Storyboard,結束State時一併關閉Storyboard。然而,VisualState.Name需要對應於TemplateVisualStateAttribute中的值。
1: <!-- 定義在MouseOver的VisualState啟動時,更改Button的BorderBrush的顏色,
2: 並且使用ColorAnimation.-->
3: <VisualState x:Name="MouseOver">
4: <Storyboard>
5: <ColorAnimation Storyboard.TargetName="BorderBrush"
6: Storyboard.TargetProperty="Color" To="Red" />
7: </Storyboard>
8: </VisualState>
‧TemplateVisualStateAttribute:
為何VisualState.Name需要對應TemplateVisualStateAttribute?根據<Customizing Other Controls by Understanding the Control Contract>
內容提及一個Control要有這些VisualState的控件,在實作Control Contract時即需要透過TemplateVisualState去定義要支援的State與Group,
如下範例:
1: [TemplateVisualState(Name = "Normal", GroupName = "CommonStates")]
2: [TemplateVisualState(Name = "MouseOver", GroupName = "CommonStates")]
3: [TemplateVisualState(Name = "Pressed", GroupName = "CommonStates")]
4: [TemplateVisualState(Name = "Disabled", GroupName = "CommonStates")]
5: [TemplateVisualState(Name = "Unfocused", GroupName = "FocusStates")]
6: [TemplateVisualState(Name = "Focused", GroupName = "FocusStates")]
7: public class Button : ButtonBase
8: {
9: //在上方訂了支援Normal, MouseOver, Pressed, Disable, Unfocused, Focused
10: //並分配至CommonStates與FocusStates二種Groups
11: }
12:
TemplateVisualStateAttribute.GroupName收納有多少的States屬相同的Groups,States在相同的Group內是互相排斥可讓狀態獨立性。
另外,它們的階層是:Visual State < Visual State Group < VisualStateManager.VisualStateGroups,因此如果今天要新增一個新的State,
則需要一層層往上註冊,讓VisualStateManager可管理到Visual State與觸發定義好的樣式。如下範例:
1: <ControlTemplate TargetType="Button">
2: <Border x:Name="RootElement">
3: <!-- 修改Visaul State裡內容 -->
4: <VisualStateManager.VisualStateGroups>
5:
6: <!-- CommonStates屬於常見的States集合,定義相關的States。裡面States彼此之間是互斥的-->
7: <VisualStateGroup x:Name="CommonStates">
8:
9: <!-- Normal State代表Button的在正常狀態下。 目前被觸發的是其他人的VisualStateGroups-->
10: <VisualState x:Name="Normal" />
11:
12: <!-- 修改在MouseOver的State被啟動時,透過ColorAnimation修改BorderBrush的顏色-->
13: <VisualState x:Name="MouseOver">
14: <Storyboard>
15: <ColorAnimation Storyboard.TargetName="BorderBrush"
16: Storyboard.TargetProperty="Color" To="Red" />
17: </Storyboard>
18: </VisualState>
19:
20: <!-- 修改在Pressed的State被啟動時,轉換BorderBrush的顏色為透明-->
21: <VisualState x:Name="Pressed">
22: <Storyboard >
23: <ColorAnimation Storyboard.TargetName="BorderBrush"
24: Storyboard.TargetProperty="Color" To="Transparent"/>
25: </Storyboard>
26: </VisualState>
27: </VisualStateGroup>
28: </VisualStateManager.VisualStateGroups>
29:
30: <Border.Background>
31: <SolidColorBrush x:Name="BorderBrush" Color="Black"/>
32: </Border.Background>
33:
34: <Grid Background="{TemplateBinding Background}" Margin="4">
35: <ContentPresenter
36: HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
37: VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
38: Margin="4,5,4,4" />
39: </Grid>
40: </Border>
41: </ControlTemplate>
4. Specifying the Behavior of a Control When It Transitions Between States:
接下來談論的是在指定States交換時的行為。舉上述例子而言,當進入Button時,按鈕的邊框變成了紅色,長按超過1秒,
邊框變成了透明。由於Animation預設需要1秒鐘才會觸發,加上Click是很快速的切換Visual State造成影響是很難感覺到的。
因此,為了讓用戶設定每個Visual State觸發狀態的時間長度進一步順暢地連接起其他Visual State,提供了VisualTransition的
定義,使用VisualTransition需要注意以下幾點:
‧二個Visual State發生交換的過渡時間;
‧指定在交換期間控件顯示的額外變化;
‧指定那一個VisualState適用何種VisualTransition;
4-1. Specifying the Duration of a Transition:
使用GeneratedDuration屬性指定Visual State交換的過渡時間長度。舉例Button按一秒才能有效果為例,可透過定義
VisualTransition與GeneratedDuration項目,加速Button按下引發事件的速度;
4-2. Specifying Changes to the Control's Appearance During a Transition:
了解如何調整過渡時間後,接下來是為過渡時間進行時改變控件外貌。在VisualTransition內一樣可以使用Storyboard,
因此,可以在VisualTransition指定一個Storyboard的開始,等VisualState轉換完畢後再關閉;
結合4.1與4.2的說明,根據<Customizing the Appearance of an Existing Control by Using a ControlTemplate>的範例設定Button在VisualState
由MouseOver回到Normal時,Button的Border顏色由blue->yellow->black,並且持續1.5秒,如下:
1: <Button Grid.Row="0" Width="100" Height="100"
2: x:Name="btnData" Content="測試" Background="Red">
3: <Button.Template>
4: <ControlTemplate TargetType="Button" x:Name="newTemplate">
5: <Border x:Name="RootElement">
6: <VisualStateManager.VisualStateGroups>
7: <VisualStateGroup x:Name="CommonStates">
8: <VisualState x:Name="Normal" />
9: <!-- 修改在MouseOver的State被啟動時,透過ColorAnimation修改BorderBrush的顏色-->
10: <VisualState x:Name="MouseOver" />
11:
12: <!-- 修改在Pressed的State被啟動時,轉換BorderBrush的顏色為透明-->
13: <VisualState x:Name="Pressed">
14: <Storyboard >
15: <ColorAnimation Storyboard.TargetName="BorderBrush"
16: Storyboard.TargetProperty="Color" To="Transparent"/>
17: </Storyboard>
18: </VisualState>
19:
20: <VisualStateGroup.Transitions>
21: <VisualTransition From="MouseOver" To="Normal"
22: GeneratedDuration="0:0:1.5">
23: <!-- 設定一個Storyboard,分別在這1.5秒中變換3種顏色 -->
24: <Storyboard>
25: <ColorAnimationUsingKeyFrames
26: Storyboard.TargetProperty="Color"
27: Storyboard.TargetName="BorderBrush"
28: FillBehavior="HoldEnd" >
29: <ColorAnimationUsingKeyFrames.KeyFrames>
30: <!--0.5秒轉成藍色,1秒轉成黃色,1.5秒轉成黑色-->
31: <LinearColorKeyFrame Value="Blue" KeyTime="0:0:0.5" />
32: <LinearColorKeyFrame Value="Yellow" KeyTime="0:0:1" />
33: <LinearColorKeyFrame Value="Black" KeyTime="0:0:1.5" />
34: </ColorAnimationUsingKeyFrames.KeyFrames>
35: </ColorAnimationUsingKeyFrames>
36: </Storyboard>
37: </VisualTransition>
38: </VisualStateGroup.Transitions>
39: </VisualStateGroup>
40: </VisualStateManager.VisualStateGroups>
41:
42: <!--為Border建立SolidColorBrush物件,並且給予一個名稱,它可在這Template中被使用-->
43: <Border.Background>
44: <SolidColorBrush x:Name="BorderBrush" Color="White"/>
45: </Border.Background>
46:
47:
48: <!--為Grid建立不同的Background,分開與Border背景不同的顏色,Grid的Background,
49: 代表Button的Background顏色-->
50: <Grid Margin="4" x:Name="GridBrush" Background="{TemplateBinding Background}">
51:
52: <!--使用ContentPresenter呈現Button的Content-->
53: <ContentPresenter
54: HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
55: VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
56: Margin="0,0,0,0" />
57:
58: </Grid>
59: </Border>
60: </ControlTemplate>
61: </Button.Template>
62: </Button>
4-3. Specifying When a VisualTransition Is Applied:
在VisualTransition使用上可支援任何時間控件State之間的轉換,但有一些限制,透過下表來加以說明:
| Type of restriction | Value of From | Value of To |
| From a specified state to another specified state | The name of a VisualState | The name of a VisualState |
| From any state to a specified state | Not set | The name of a VisualState |
| From a specified state to any state | The name of a VisualState | Not set |
| From any state to any other state | Not set | Not set |
可配合上表檢視自己要使用的VisualTransition是否需指定From與To來加以使用,如果有指定From與To代表該VisualTransition被
啟動時機需要滿足二個設定值,如果只設定From或To,則會按照指定的VisualState來啟動。例如:
1: <!-- 在MouseOver時保持0.5秒的轉換 -->
2: <VisualTransition To="MouseOver"
3: GeneratedDuration="0:0:0.5" />
4:
5: <!-- 在Pressed轉至MouseOver時保持0.01秒的轉換 -->
6: <VisualTransition From="Pressed" To="MouseOver"
7: GeneratedDuration="0:0:0.01" />
(4) 讓Custom Control實作Parts and States Model,支援Expression Blend:
在上述說明透過XAML調整既有控件的Visual behavior、Visual structure後,最後再討論客製控件如何實作Control Contract,
以支援在Blend工具上可以直接操作客製好的控件。
Control Contract有三個元素:
‧可供控件邏輯使用的Visual Element。(例如:Button的Border、Grid…等)
‧控件具有的State與State Groups。
‧影響控件視覺的公開屬性。
往下分別三元素加以說明。
(4-1). Visual Elements in the Control Contract:
大部分Control的邏輯是繼承FrameworkElement,而具有ContentTemplate功能。客製控件時,如果希望在ContentTemplate
中找到特定的FrameworkElement,必須傳達訊息給ContentTemplate。傳達的方式透過TemplatePartAttribute指定type類型與name,
讓ContentTemplate可以得知那些FrameworkElement在客製中將會有所互動。
舉例來說:Combox中指定ContentPresenter與Popup,告訴ContentTemplate期望找到這二個控件。
1: [TemplatePartAttribute(Name = "ContentPresenter", Type = typeof(ContentPresenter))]
2: [TemplatePartAttribute(Name = "Popup", Type = typeof(Popup))]
3: public class ComboBox : ItemsControl
4: {
5: }
在程式裡指定好這二個期望物件後,即可以在XAML內容中取得相關內容,如下:
1:
2: <ControlTemplate TargetType="ComboBox">
3: <Grid>
4: <Border x:Name="ContentPresenterBorder">
5: <Grid>
6: <ToggleButton x:Name="DropDownToggle"
7: HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
8: Margin="-1" HorizontalContentAlignment="Right">
9: <Path x:Name="BtnArrow" Height="4" Width="8"
10: Stretch="Uniform" Margin="0,0,6,0" Fill="Black"
11: Data="F1 M 300,-190L 310,-190L 305,-183L 301,-190 Z " />
12: </ToggleButton>
13: <ContentPresenter x:Name="ContentPresenter" Margin="6,2,25,2">
14: <TextBlock Text=" " />
15: </ContentPresenter>
16: </Grid>
17: </Border>
18: <Popup x:Name="Popup">
19: <Border x:Name="PopupBorder"
20: HorizontalAlignment="Stretch" Height="Auto"
21: BorderThickness="{TemplateBinding BorderThickness}"
22: BorderBrush="Black" Background="White" CornerRadius="3">
23: <ScrollViewer x:Name="ScrollViewer" BorderThickness="0" Padding="1">
24: <ItemsPresenter/>
25: </ScrollViewer>
26: </Border>
27: </Popup>
28:
29: </Grid>
30: </ControlTemplate>
(4-2). States in the Control Contract:
每一個Control均有自身的Visual State可以應用,如何修改狀態呢,可參考<Changing the Appearance of a Control Depending on Its State>
的說明,有比較完整的範例與說明,包括如何建立自立的VisualSate與定義Group等。
(4-3). Properties in the Control Contract:
修改控件視覺的公開屬性也是Control Contract之一,它可以讓我們不用定義ContentTemplate可以達到視覺的調整,更可以使用
TemplateBinding的方式擴充屬性的設定。
1:
2: [TemplateVisualState(Name = "Normal", GroupName = "CommonStates")]
3: [TemplateVisualState(Name = "MouseOver", GroupName = "CommonStates")]
4: [TemplateVisualState(Name = "Pressed", GroupName = "CommonStates")]
5: [TemplateVisualState(Name = "Disabled", GroupName = "CommonStates")]
6: [TemplateVisualState(Name = "Unfocused", GroupName = "FocusStates")]
7: [TemplateVisualState(Name = "Focused", GroupName = "FocusStates")]
8: public class Button : ButtonBase
9: {
10: public static readonly DependencyProperty BackgroundProperty;
11: public static readonly DependencyProperty BorderBrushProperty;
12: public static readonly DependencyProperty BorderThicknessProperty;
13: public static readonly DependencyProperty ContentProperty;
14: public static readonly DependencyProperty ContentTemplateProperty;
15: public static readonly DependencyProperty FontFamilyProperty;
16: public static readonly DependencyProperty FontSizeProperty;
17: public static readonly DependencyProperty FontStretchProperty;
18: public static readonly DependencyProperty FontStyleProperty;
19: public static readonly DependencyProperty FontWeightProperty;
20: public static readonly DependencyProperty ForegroundProperty;
21: public static readonly DependencyProperty HorizontalContentAlignmentProperty;
22: public static readonly DependencyProperty PaddingProperty;
23: public static readonly DependencyProperty TextAlignmentProperty;
24: public static readonly DependencyProperty TextDecorationsProperty;
25: public static readonly DependencyProperty TextWrappingProperty;
26: public static readonly DependencyProperty VerticalContentAlignmentProperty;
27:
28: public Brush Background { get; set; }
29: public Brush BorderBrush { get; set; }
30: public Thickness BorderThickness { get; set; }
31: public object Content { get; set; }
32: public DataTemplate ContentTemplate { get; set; }
33: public FontFamily FontFamily { get; set; }
34: public double FontSize { get; set; }
35: public FontStretch FontStretch { get; set; }
36: public FontStyle FontStyle { get; set; }
37: public FontWeight FontWeight { get; set; }
38: public Brush Foreground { get; set; }
39: public HorizontalAlignment HorizontalContentAlignment { get; set; }
40: public Thickness Padding { get; set; }
41: public TextAlignment TextAlignment { get; set; }
42: public TextDecorationCollection TextDecorations { get; set; }
43: public TextWrapping TextWrapping { get; set; }
44: public VerticalAlignment VerticalContentAlignment { get; set; }
45: }
更多詳細介紹怎麼客製Control與定義Control Contract可參考<Customizing the Appearance of an Existing Control by Using a ControlTemplate>。
[補充]
‧上述說明的Parts and States Model只是建議客製控件的一種做法,它並非由Silverlight Runtime所需的,並非一定要按此實作,
但是如想在Expression Blend上使用,即需要實作Parts and States Model Pattern。
‧ContentPresenter、ContentPresenterBorder、DropDownToggle:
透過下圖加以說明:

| 組名名稱 | 說明 |
| (1) ContentPresenter | 強制項目,用途是顯示目前的項目。如果將一些內容放入範本中的 ContentPresenter組件,只要沒有選取項目,就會顯示此內容。 |
| (2) ContentPresenterBorder | 如果 IsHitTestVisible為 True,則可以按一下 ContentPresenterBorder組件來開啟和關閉快顯視窗,而且快顯視窗將位於 ContentPresenterBorder (2) 左下角。版面配置面板對 ContentPresenterBorder組件來說是不錯的選擇。 |
| (3) DropDownToggle | 選用項目,但這可當作開啟和關閉快顯視窗的另一種方式。 |
| (4) Popup | 強制項目。這是在其中顯示項目的組件。 ItemsPresenter可用來指定顯示項目的位置。 ItemsPresenter應置於 ScrollViewer組件內。 Popup的開啟位置相對於範本根物件的界限。 |
======
以上是整理<Customizing the Appearance of an Existing Control by Using a ControlTemplate>一文中描述如何了解
ContentTemplate的使用方式。由於客製Control還有相關Control Contract的部分是開發人員在實作新的XAML控
件時需要特別注意的地方。希望對大家有所幫助。
References:
‧建立系統控制項可重複使用的範本 (Blend教學檔)
‧Customizing the Appearance of an Existing Control by Using a ControlTemplate (重要)
‧Creating a New Control by Creating a ControlTemplate
‧Walkthrough: Customizing the Appearance of a Button by Using a ControlTemplate
‧Customizing Other Controls by Understanding the Control Contract
‧Applying a ContentTemplate via C# Trigger
‧Getting Started with Controls
‧Control Styles and Templates (重要的參考,列出控件可使用的Styles與Templates)




