復合控件:將現有的各種控件組合起來(lái),形成一個(gè)新的控件,將集中控件的功能集中起來(lái)。
擴展控件:在現有控件的控件的基礎上派生出一個(gè)新的控件,為原有控件增加新的功能或者修改原有控件的控能。
自定義控件:直接從System.Windows.Forms.Control類(lèi)派生出來(lái)。Control類(lèi)提供控件所需要的所有基本功能,包括鍵盤(pán)和鼠標的事件處理。自定義控件是最靈活最強大的方法,但是對開(kāi)發(fā)者的要求也比較高,你必須為Control類(lèi)的OnPaint事件寫(xiě)代碼,你也可以重寫(xiě)Control類(lèi)的WndProc方法,處理更底層的Windows消息,所以你應該了解GDI+和Windows API。
控件最大的特點(diǎn)就是具有設計時(shí)的UI界面了。同時(shí)控件的屬性設置也是很重要的一方面。
一、控件的Attribute
CategoryAttribute:指定當屬性 (Property) 或事件顯示在一個(gè)設置為“按分類(lèi)順序”模式的 System.Windows.Forms.PropertyGrid 控件中時(shí),用于給屬性或事件分組的類(lèi)別的名稱(chēng)。




如果為屬性設置了默認值,那么修改了屬性的值以后,這個(gè)值在Property Explorer中會(huì )以粗體顯示。當VS進(jìn)行控件的串行化時(shí),他會(huì )判斷哪些不是默認值,只有不是默認值的屬性才會(huì )被串行化,所以為屬性提供默認值,可以大大減少串行化的屬性數目,提高效率。
簡(jiǎn)單屬性:
private String _displayText = "Hello World!";
[Browsable(true)]
[DefaultValue("Hello World")]
public String DisplayText
{
get
{
return _displayText;
}
set
{
_displayText = value;
Invalidate();
}
}
對于這些簡(jiǎn)單類(lèi)型的屬性,只要使用DefaultValue,并在其構造函數里傳入默認值即可。
復雜屬性:
對于復雜的類(lèi)型,比如Font,Color,你不能夠直接將這些類(lèi)型的值傳遞給Attibute的構造函數。相反你應該提供Reset<PropertyName> 和ShouldSerialize<PropertyName>方法,比如有個(gè)BackgroundColor的屬性,那么應該有下面兩個(gè)方法:ResetBackgroundColor(),ShouldSerializeBackgroundColor()。VS能夠根據方法的名稱(chēng)來(lái)識別這種方法,比如Reset<PropertyName>方法把重置為默認值,ShouldSerialize<PropertyName>方法檢查屬性是否是默認值。過(guò)去我們把它稱(chēng)之為魔術(shù)命名法,應該說(shuō)是一種不好的編程習慣,可是現在微軟依然使用這種機制。
當然,默認值設置了以后,還需要給我們的屬性設置默認顯示的值。通過(guò)給屬性賦值實(shí)現,比如:private String _displayText = "Hello World!";
DefaultValue設置的默認值不會(huì )在屬性瀏覽器中顯示;
屬性私有字段設置的“值”,會(huì )在屬性瀏覽器中默認顯示。
如果設置成兩個(gè)值相同,那么在屬性瀏覽器里就不是粗體,否則是粗體顯示。
大家要區別兩個(gè)關(guān)鍵詞: “默認值”,“默認顯示的值”
另外一種給復雜屬性設置默認值的方式:
private Color _back = Color.Red;
[Browsable(true)]
[DefaultValue(typeof(Color), "Blue")]
public Color Back
{
get { return _back; }
set { _back = value; }
}
EditorAttribute:為屬性指定一個(gè)特殊的編輯器。
1.為了能夠為這個(gè)屬性編輯提供一個(gè)界面,我們需要實(shí)現自己的彈出式編輯對話(huà)框。如圖:

當然,這僅僅是一個(gè)窗體,還不是什么屬性編輯器,每一個(gè)屬性的編輯器都是直接或者間接派生于UITypeEditor的,開(kāi)發(fā)環(huán)境也不會(huì )直接調用我們的窗體,而是調用UITypeEditor的某些虛方法,所以我們還必須提供一個(gè)派生于UITypeEditor的累來(lái)與開(kāi)發(fā)環(huán)境通信。
派生UITypeEditor以后,我們需要重寫(xiě)兩個(gè)非那根發(fā),一個(gè)是GetEditStyle,另一個(gè)是EditValue。前者通知開(kāi)發(fā)環(huán)境,屬性的編輯是一個(gè)模式對話(huà)框;后者是核心方法,通過(guò)上下文環(huán)境獲得正在編輯的控件的實(shí)例,并將實(shí)例的Scope屬性傳遞給屬性編輯對話(huà)框,顯示對話(huà)框供給用戶(hù)編輯屬性的值。
[Editor(typeof(ScopeEditor), typeof(UITypeEditor))]
2.提供下拉屬性編輯器
制作一個(gè)用戶(hù)控件,當做屬性的編輯頁(yè)面:

和模態(tài)對話(huà)框編輯器一樣,開(kāi)發(fā)環(huán)境并不會(huì )直接調用我們的編輯器控件,而是用過(guò)UITypeEditor類(lèi)的派生來(lái)實(shí)現編輯器的調用,所以我們必須實(shí)現一個(gè)下拉式編輯器。

[Editor(typeof(ScopeDropDownEditor), typeof(UITypeEditor))]
LocalizableAttribute:指示一個(gè)屬性是否能被本地化,任何有這個(gè)Attribute的屬性將會(huì )被持久化到資源文件里。
DesignerSerializationVisibilityAttribute:指示一個(gè)屬性是否或者如何持久化到代碼里。
是一個(gè)枚舉值:一共有三種類(lèi)型:Content,Hidden,Visible。Content指示代碼生成器為對象包含的內容生成代碼,而不是為對象本身;Hidden指示代碼生成器不為對象生成代碼;visible指示代碼生成器為對象生成代碼。假如你的控件有一個(gè)集合屬性,又想在設計時(shí)自動(dòng)將集合屬性的內容生成代碼,那么就使用這個(gè)Attribute,并將值設為DesignerSerializationVisibility.Content。
假設一個(gè)自定義控件中有Item的集合屬性:

在設計時(shí),可以添加,刪除

我們看添加完以后的代碼,會(huì )發(fā)現,內容被序列化到資源文件里了。

我們可以添加DesignerSerializationVisibilityAttribute
[DesignerSerializationVisibilityAttribute(
DesignerSerializationVisibility.Content)]
查看代碼:

我們可以發(fā)現被序列化到了源代碼里。
TypeConverterAttribute:為屬性指定一個(gè)類(lèi)型轉換器,類(lèi)型轉換器能將屬性的值轉化成其它的數據類(lèi)型。如果屬性是自定義類(lèi)型或者特殊類(lèi)型,那么就得自己實(shí)現轉換器,并通過(guò)TypeConvertAttribute去實(shí)現了。類(lèi)型轉換器都是從System.ComponentModel.TypeConverter派生出來(lái)的。
1.要實(shí)現一個(gè)類(lèi)型轉換器,我們必須要重寫(xiě)(override)四個(gè)方法:
CanConvertFrom()――根據類(lèi)型參數進(jìn)行測試,判斷是否能從這個(gè)類(lèi)型轉換成當前類(lèi)型,在本例中我們只提供轉換string和InstanceDescriptor類(lèi)型的能力。
CanConvertTo()――根據類(lèi)型參數進(jìn)行測試,判斷是否能從當前類(lèi)型轉換成指定的類(lèi)型。
ConvertTo()――將參數value的值轉換為指定的類(lèi)型。
ConvertFrom()――串換參數value,并返回但書(shū)類(lèi)型的一個(gè)對象。

2.為了在屬性瀏覽器里能夠獨立的編輯子屬性,我們還要重寫(xiě)兩個(gè)方法:GetPropertiesSupported()和GetProperties();

DefaultEventAttribute:為組件指定一個(gè)默認的事件,當用戶(hù)在form設計其中選擇一個(gè)控件的時(shí)候,在屬性瀏覽器中這個(gè)事件被選中。
聯(lián)系客服