為快速地為你的 應用 定制一個零部件,你需要的是UserControl,這可以參考在WPF中自定義控件 UserControl, 為了讓你打造的控件更标準化,更靈活以及更具有普遍意義,你需要用到的CustomControl,這正是本文要介紹的.
1、建立CustomControl
在選擇控件基類後,第一件事情便是在你的項目中建立"CustomControl",我們會發現在項目中自動生成了一個*.CS(或*.VB或其他)檔案以及ThemesGeneric.xaml(如果原來沒有的話),他們分别是CustomControl的背景代碼檔案(Code Behind)與控件的預設主題檔案,打開ThemesGeneric.xaml,你會發現其中自動生成了一個Style,這是你的控件的預設樣式,正如WPF内置控件也有它的預設樣式一樣.這時,我們的工作就被分成了兩個部分,一是在XXX.cs檔案中編輯控件 邏輯 ,而是在Generic.xaml中編寫其UI.
2、Generic.xaml中的Style是如何與我們的控件聯系在一起的
打開XXX.cs檔案,你會發現靜态構造方法中,VS自動地幫你覆寫了控件的DefaultStyleKey值:
static CustomControl1()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomControl1), new FrameworkPropertyMetadata(typeof(CustomControl1)));
}
我們知道DefaultStyleKeyProperty是FrameworkElement以及FrameworkContentElement類用來訓示控件的預設樣式鍵值的屬性,該屬性有一個很特别的地方就是我們不能夠用繼承的思想來思考它,比如說Button的預設樣式鍵值是Style1,其子類MyButton的預設樣式鍵值是Style2(或者沒有指定預設樣式),盡管MyButton可以向上轉型成Button類,但我們并不希望其轉型後的預設樣式鍵值為Style1.是以WPF采用了在子類控件的靜态構造方法中重寫DefaultStyleKey元 資料 的方式來指定該子類控件的預設樣式.上面代碼中,我們将new FrameworkPropertyMetadata(typeof(CustomControl1))指定為其新的中繼資料值,這個值代表着,我們将在資源字典中查找一個鍵值為typeof(CustomControl1)的Style來做為控件的預設樣式.而這個樣式剛好被我們定義在了Generic.xaml中:
<Style TargetType="">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="">
<Border Background=""
BorderBrush=""
BorderThickness="">
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
這是大家可能有個疑問,上面XAML中的Style并沒有指定Key值啊,而我們的控件要求的預設樣式Key值為typeof(CustomControl1), 并且資源字典中的元素肯定是要有Key的? 這是Style的基本知識了,在WPF中,為Style指定Key時有兩種方式:一是明确指定Key,而是在沒有明确指定Key的情況下指定TargetType,WPF會自動地将其可Key設定為typeof(TargetType).如果你有在Blend中為控件打造Style的經驗的話,你會注意到建立一個Style時,Blend會提供一個"Apply to ALL"選項,這也是為什麼你打造的Style可以"Apply to all"的奧秘所在.
3、 "Generic.xaml"這個名稱并非偶然
通過上面的叙述,你可能會有沖動将Generic.xaml中的Style代碼剪切出來,粘貼到任何一個我們的控件可以找到的地方,然後把Generic.xaml删掉或改成更優雅的名稱,如果你運氣好的話,這是可行的,因為控件會自下而上(Page,App,Theme)去查找其所需要的Style,但此時你已經犯了一個潛在的錯誤:你沒有為控件提供預設的樣式.這裡的預設樣式其實是說"在預設主題中或沒有為該控件找到目前操作 系統 對應的主題時采用的的樣式".這涉及到WPF中Theme的相關話題了,有興趣可以參考msdn相關SDK.
4、打造你的控件邏輯
這是必然的,添加屬性,添加事件,方法等等,這些你可以參考在WPF中自定義控件 UserControl ,這裡就不重複叙述了.
5、打造控件UI
這裡值得一提的是我非常佩服在VS的XAML海洋裡"裸泳"的兄弟們,不過我更推薦使用Microsoft Expression Blend來完成這項艱巨的任務.另外,如果你發現WPF内置控件在Blend中很好用而我們自己打造的控件卻不是這樣,那麼請注意了,你的控件邏輯可能 設計 得不規範.
6、控件UI部分與邏輯部分的耦合度
這是一個容易被忽略但卻非常重要的問題, 我們之是以使用CustomControl而不是UserControl,是因為我們希望自己的控件能向WPF内置控件一樣,其UI能輕易地被其他使用者定制或我們将來所改變.也就是說其視覺樹不能與背景邏輯糾纏在一起,因為其視覺樹中的元素完全可能被你的控件使用者改變.比如,如果你的控件的視覺樹中有一個Button,而你在該Button的Click事件中做了一些控件的邏輯處理,那麼很可能你的控件打造失敗了,因為該Button可能會在使用者重新定義控件Template時被删除.