本系列的前面幾篇文章講解了如何來定義屬性以及更有效編輯屬性,接下來我要講一下控制項屬性的預設值。如果我們希望自己開發的控制項更易於被其它開發人員使用,那麼提供預設值是非常值得的。
如果你為屬性設定了預設值,那麼當開發人員修改了屬性的值,這個值在Property Explorer中將會以粗體顯示。VS為屬性提供一個操作功能表,允許程式員使用控制項把值重設為預設值。當VS進行控制項的序列化時,他會判斷那些值不是預設值,只有不是預設值的屬性才會被序列化,所以為屬性提供預設值時可以大大減少序列化的屬性數目,提高效率。
那麼VS怎麼知道我們的屬性值不是預設值了呢?我們需要一種機制來通知VS預設值。實現這種機制有兩種方法:
對於簡單類型的屬性,比如Int32,Boolean等等這些Primitive類型,你可以在屬性的聲明前設定一個DefaultValueAttribute,在Attribute的建構函式裡傳入預設值。
對於複雜的類型,比如Font,Color,你不能夠直接將這些類型的值傳遞給Attibute的建構函式。相反你應該提供Reset<PropertyName> 和ShouldSerialize<PropertyName>方法,比如ResetBackgroundColor(),ShouldSerializeBackgroundColor()。VS能夠根據方法的名稱來識別這種方法,比如Reset<PropertyName>方法把重設為預設值,ShouldSerialize<PropertyName>方法檢查屬性是否是預設值。過去我們把它稱之為魔術命名法,應該說是一種不好的編程習慣,可是現在微軟依然使用這種機制。我還是以前面幾篇文章使用的例子代碼。
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.ComponentModel;
using System.Drawing;
namespace CustomControlSample
{
public class FirstControl : Control
{
private String _displayText=”Hello World!”;
private Color _textColor=Color.Red;
public FirstControl()
{
}
// ContentAlignment is an enumeration defined in the System.Drawing
// namespace that specifies the alignment of content on a drawing
// surface.
private ContentAlignment alignmentValue = ContentAlignment.MiddleLeft;
[
Category("Alignment"),
Description("Specifies the alignment of text.")
]
public ContentAlignment TextAlignment
{
get
{
return alignmentValue;
}
set
{
alignmentValue = value;
// The Invalidate method invokes the OnPaint method described
// in step 3.
Invalidate();
}
}
[Browsable(true)]
[DefaultValue(“Hello World”)]
public String DisplayText
{
get
{
return _displayText;
}
set
{
_displayText =value;
Invalidate();
}
}
[Browsable(true)]
public Color TextColor
{
get
{
return _textColor;
}
set
{
_textColor=value;
Invalidate();
}
}
public void ResetTextColor()
{
TextColor=Color.Red;
}
public bool ShouldSerializeTextColor()
{
return TextColor!=Color.Red;
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
StringFormat style = new StringFormat();
style.Alignment = StringAlignment.Near;
switch (alignmentValue)
{
case ContentAlignment.MiddleLeft:
style.Alignment = StringAlignment.Near;
break;
case ContentAlignment.MiddleRight:
style.Alignment = StringAlignment.Far;
break;
case ContentAlignment.MiddleCenter:
style.Alignment = StringAlignment.Center;
break;
}
// Call the DrawString method of the System.Drawing class to write
// text. Text and ClientRectangle are properties inherited from
// Control.
e.Graphics.DrawString(
DisplayText,
Font,
new SolidBrush(TextColor),
ClientRectangle, style);
}
}
}
在上面的代碼中,我增加了兩個屬性,一個是DisplayText,這是一個簡單屬性,我們只需要在它的聲明前添加一個DefaultValue Attribute就可以了。另外一個是TextColor屬性,這個複雜類型的屬性,所以我們提供了ResetTextColor和ShouldSerializeTextColor來實現預設值。
預設值的實現就講完了,但是有一點不要忽視了,你設定了預設值,就應該相應的初始化這些屬性,比如我們例子中的代碼:
private String _displayText=”Hello World!”;
private Color _textColor=Color.Red;