WPF自定义控件
參考自:http://www.cnblogs.com/zhouyinhui/archive/2007/12/01/979715.html<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
1. User Control和Custom Control
?? 在新建一個Project的時候,WPF提供了2種自定義控件的模板:WPF User Control Library和WPF Custom Control Library。User Control就像是winform中的自定義控件方式,可以理解為將多個已有的控件拼湊起來,在后臺代碼中直接訪問這些子元素,缺點是對模板和樣式的支持不好。它自動的從System.Windows.Controls.UserControl繼承。
?? Custom Control,其開發(fā)出來的控件才真正具有WPF風格,其對模板樣式有著很好的支持,這是因為打造CustomControl時做到了邏輯代碼與外觀相分離,即使換上一套完全不同的視覺樹其同樣能很好的工作,就像WPF內置的控件一樣。
?? 在使用Visual Studio打造控件時,UserControl與CustomControl的差別就更加明顯,在項目中添加一個UserControl時,我們會發(fā)現(xiàn)設計器為我們添加了一個XAML文件以及一個對應的.CS文件,然后你就可以像設計普通窗體一樣設計該UserControl;如果我們是在項目中添加CustomControl,情況卻不是這樣,設計器會為我們生成一個.CS文件,該文件用于編寫控件的后臺邏輯,而控件的外觀卻定義在了軟件的應用主題(Theme)中了(如果你沒有為軟件定義通用主題,其會自動生成一個通用主題themes\generic.xaml,然后主題中會自動為你的控件生成一個Style),并將通用主題與該控件關聯(lián)了起來。這也就是CustomControl對樣式的支持度比UserControl好的原因。
在generic.xaml中我們需要定義該控件的默認主題,這就像是WPF內置的控件一樣,他們有自己的默認的主題。然后我們需要做的工作就是在.cs文件中編寫后臺邏輯,在generic.xaml中編寫默認的UI。
CustomControl會從System.Windows.Controls.Control繼承,如下:
??? public class CustomControl1 : Control
??? {
??????? static CustomControl1()
??????? {
??????????? DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomControl1), new FrameworkPropertyMetadata(typeof(CustomControl1)));
??????? }
}
它總有一個Static的構造方法,并自動調用DefaultStyleKeyProperty.OverrideMetadata 方法。DefaultStyleKey是指當有theme style定義或應用的時候,用它來指定該控件的默認樣式,為該metadata的defaultvalue指定為typeof(CustomControl1),這個值代表著,我們將在資源字典中查找一個鍵值為typeof(CustomControl1)的Style來做為控件的默認樣式.而這個樣式剛好被我們定義在了Generic.xaml中:
??? <Style TargetType="{x:Type local:CustomControl1}">
??????? <Setter Property="Template">
??????????? <Setter.Value>
??????????????? <ControlTemplate TargetType="{x:Type local:CustomControl1}">
??????????????????? <Border Background="{TemplateBinding Background}"
?????????????????????????? ?BorderBrush="{TemplateBinding BorderBrush}"
?????????????????????? ?????BorderThickness="{TemplateBinding 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)。
另外,如果不希望element或者control用默認的主題style,可以設置OverridesDefaultStyle為true。
2. 使用TemplatePartAttribute特性
?? TemplatePartAttribute用在一個控件類的定義前面,控件的作者通過它來告訴template的作者在控件的模板中必須有TemplatePart中指定的類型和名稱的元素,這個控件才能正常工作。當然該特性只是為了標識這一個行為,如果不寫,也不會報錯的。
?? 例如我們看WPF Toolkit中的Calendar類,定義如下:
??? [TemplatePart(Name = Calendar.ElementRoot, Type = typeof(Panel))]
??? [TemplatePart(Name = Calendar.ElementMonth, Type = typeof(CalendarItem))]
??? public partial class Calendar : Control
??? {
??????? #region Constants
?
??????? private const string ElementRoot = "PART_Root";
??????? private const string ElementMonth = "PART_CalendarItem";
…
}
?
?? 在generci.xaml中可以看到如何使用:
<Setter Property="Template">
??????????? <Setter.Value>
??????????????? <ControlTemplate TargetType="local:Calendar">
??????????????????? <StackPanel Name="PART_Root" HorizontalAlignment="Center">
??????????????????????? <primitives:CalendarItem
?????????????????????????? ?Name="PART_CalendarItem"
?????????????????????????? ?Style="{TemplateBinding CalendarItemStyle}"
?????????????????????????? ?Background="{TemplateBinding Background}"
?????????????????????????? ?BorderBrush="{TemplateBinding BorderBrush}"
?????????????????????????? ?BorderThickness="{TemplateBinding BorderThickness}"???????????????????????????
?????????????????????????? ?/>
??????????????????? </StackPanel>
??????????????? </ControlTemplate>
??????????? </Setter.Value>
??????? </Setter>
另外我們可以在OnApplyTemplate 通過GetTemplateChild方法來得到相應的元素,注意GetTemplateChild方法過時了,用System.Windows.FrameworkTemplate.FindName(System.String,System.Windows.FrameworkElement)代替它。
????? public override void OnApplyTemplate()
??????? {
??????????? if (_monthControl != null)
??????????? {
??????????????? _monthControl.Owner = null;
??????????? }
?
??????????? base.OnApplyTemplate();
?
??????????? _monthControl = GetTemplateChild(ElementMonth) as CalendarItem;
?
??????????? if (_monthControl != null)
???? ???????{
??????????????? _monthControl.Owner = this;
??????????? }
?
??????????? this.CurrentDate = this.DisplayDate;
??????????? UpdateCellItems();
??????? }
?
?? 為了實現(xiàn)效果隨著用戶操作系統(tǒng)主題改變而動態(tài)改變,你至少有兩種方法來實現(xiàn):(1)監(jiān)聽系統(tǒng)消息WM_THEMECHANGE,然后切控件界面.(2)將系統(tǒng)主題對應的Style放置在控件解決方案的themes文件夾下,比如與Vista Aero向對應的放在themes\Aero.NormalColor.xaml,與藍色的Windows XP主題對應的放在themes\Luna.NormalColor.xaml,與Window經典主題相對應的放在themes\Classic.xmal,相信大家已經看出規(guī)律:themes\主題名.顏色名.xaml,其中經典主題沒有顏色名.這樣當用戶切換主題時我們的控件就會切換到對應的Style,如果我們沒有提供用戶當前的主題所對應的樣式則調用themes\Generic.xaml。
?
?? 另外需要說明的是AssemblyInfo中的ThemeInfoAttribute,結構大概如下:
[assembly:ThemeInfo(
??? // Specifies the location of theme specific resources
??? ResourceDictionaryLocation.SourceAssembly,
??? // Specifies the location of non-theme specific resources:
ResourceDictionaryLocation.SourceAssembly)]
?
當一個Assembly被該特性標識后,我們可以稱它為Themed assembly,注意ResourceDictionaryLocation有三個枚舉值,None,SourceAssembly和ExternalAssembly,None指不用themes;SourceAssembly指定ResourceDictionaries存在于將要被themed的控件所在的Assembly中;ExternalAssembly指ResourceDictionaries存在于其他程序集中,但不包括將要被themed的控件所在的Assembly。
ThemeInfo的第一個參數(shù)指定和操作系統(tǒng)主題相關的ResourceDictionaries,如果為None則表示不隨操作系統(tǒng)的主題變化而變化。第二個參數(shù)指generic主題所在位置,也就是generic.xaml,注意第一個參數(shù)的優(yōu)先級高,也就是說如果沒有找到和操作系統(tǒng)相應的主題,才會去找有沒有generic.xaml。
這里有一個例子,參考自http://www.cnblogs.com/yuxs/archive/2007/05/24/758863.html,是一個WPF 的日歷控件,點擊這里下載我的測試solution。
posted on 2008-12-26 10:02 cutebear 閱讀(...) 評論(...) 編輯 收藏轉載于:https://www.cnblogs.com/bear831204/archive/2008/12/26/1360757.html
總結
- 上一篇: java元素定位div_Java+Sel
- 下一篇: mysql80连接不上本地服务器_小白教