1. 控件屬性基本概念
本小節介紹有關創建服務器控件屬性的基本內容,具體內容包括:(1)屬性類型和形式;(2)從Control和WebControl繼承的屬性;(3)與屬性相關的設計時元數據attribute。
1) 屬性類型和形式
通常情況下,服務器控件屬性可以分爲兩種類型:簡單屬性和複雜屬性。
簡單屬性是指屬性值可以很容易轉換爲字符串表達式的屬性,這種屬性的值通常爲Boolean、Byte、Char、Double、Enum、Int32、DateTime等簡單數值類型,以及String類型和枚舉類型。開發人員可以通過添加代碼,將簡單屬性存儲在ViewState字典中,以在回發間進行狀態管理。如果一個屬性的類型是本身具有屬性(稱爲子屬性)的類,則該屬性就稱爲複雜屬性。例如,WebControl類的Font屬性的類型是本身具有屬性(如Bold和Name)的FontInfo類。Bold和Name是WebControl的Font屬性的子屬性。ASP.NET頁框架可通過使用帶有連字符的語法(例如Font-Bold="true")在控件的開始標記上保存子屬性,但如果在控件的標記(例如<font Bold="true">)中保存子屬性,則子屬性在頁中的可讀性更強。
在上文中談到了屬性的標記形式,即添加連字符的形式。實際上,不同的屬性表現出不同的標記形式。爲了加深對簡單屬性和複雜屬性的認識,下面介紹一下有關屬性的4種標記形式。
· 通用形式屬性
這是一種最爲常見的屬性標記形式。這種形式的屬性標記位於控件內部,與runat="server"一起定義。通常爲以下形式:
<MyControl:CustomerControl id="demo1" runat="server" PropertyName="PropertyValue"/> |
其中PropertyName爲一個不帶連字符的單詞。例如:
<asp:Button id="button1" runat="server" Text="Submit"/> |
此處的屬性Text屬於通用形式屬性。
· 連字符形式屬性
這種標記形式的屬性位於控件標記內部,帶有連字符是這種形式屬性的最大特徵。其形式爲:
<MyControl:CustomerControl id="demo1" runat="server" Sub-PropertyName="PropertyValue"/> |
其中Sub-PropertyName爲一個帶連字符的單詞組合。例如:
<asp:Label id="label1" runat="server" Font-Size="Medium" Font-Underline="True" /> |
在上面的代碼中,Font-Size和Font-Underline就是典型的連字符形式屬性。
· 內部嵌套形式屬性
凡是具有這種標記形式的屬性均爲複雜屬性。它是以嵌套形式在控件標記內部聲明某屬性集的子屬性。其形式類似:
<asp:DataGrid id="DataGrid1" runat="server"> <HeaderStyle ForeColor="#FFFFCC" BackColor="#990000"> </HeaderStyle> <FooterStyle ForeColor="#330099" BackColor="#FFFFCC"> </FooterStyle> </asp:DataGrid> |
其中HeaderStyle是內部嵌套形式屬性,ForeColor和BackColor是HeaderStyle屬性的子屬性。FooterStyle與HeaderStyle是一樣的,也是內部嵌套形式屬性。
· 內部嵌套形式默認屬性
這種標記形式的屬性通常用於服務器控件的集合屬性,具有這種形式的屬性必然是複雜屬性。該形式屬性與上文所述"內部嵌套形式屬性"的標記形式基本相同。不同之處在於:當某控件具有這種屬性時,控件標記中只包含該形式屬性,不能包含其他任何屬性。這就是爲什麼稱爲"默認"的原因。其形式類似:
<asp:DropDownList id="DropDownList1" runat="server"> <asp:ListItem>1</asp:ListItem> <asp:ListItem>2</asp:ListItem> <asp:ListItem>3</asp:ListItem> <asp:ListItem>4</asp:ListItem> </asp:DropDownList> |
其中屬性ListItem就是典型的內部嵌套形式默認屬性。
2) 從Control和WebControl繼承的屬性
如前面文章所述,如果需要開發沒有UI的控件或者組合其他呈現它們自己的UI的控件,則從System.Web.UI.Control基類派生。爲此,讀者應該瞭解一些Control類的常見屬性。如表1列舉了Control基類常用屬性,它們在開發服務器控件過程中經常被使用。
屬性 | 數據類型 | 說明 |
Controls | ControlCollection | 獲取 ControlCollection 對象,該對象表示 UI 層次結構中指定服務器控件的子控件 |
Adapter | ControlAdapter | 獲取控件的瀏覽器特定適配器。(asp.net 2.0新增) |
AppRelativeTemplateSourceDirectory | string | 獲取或設置包含該控件的 Page 或 UserControl 對象的應用程序相對虛擬目錄。(asp.net 2.0新增) |
EnableTheming | bool | 獲取或設置一個值,該值指示是否對此控件應用主題。(asp.net 2.0新增) |
Page | Page | 獲取對包含服務器控件的 Page 實例的引用。 |
Parent | Control | 控件屬於其Controls集合的控件。(如果控件B是A.Controls的一個元素,則控件A是控件B的父級) |
EnableViewState | Bool | 指示控件在往返過程中是否維護其視圖狀態。如果父控件不維護其視圖狀態,則自動不維護其子控件的視圖狀態 |
TemplateControl | TemplateControl | 獲取或設置對包含該控件的模板的引用。(asp.net 2.0新增) |
UniqueID | String | 頁框架給控件分配的分層限定的唯一標識符 |
ClientID | String | 給控件分配的唯一標識符,該唯一標識符在客戶端上呈現爲HTML ID特性。ClientID與UniqueID是不同的,這是因爲UniqueID可以包含冒號字符(:),而在HTML ID特性中該字符無效(並且不允許在客戶端腳本的變量名中使用) |
頁框架
如前面文章所述,如果創建具有UI的自定義服務器控件,則應該從WebControl或System.Web.UI.WebControls中的任何控件派生,該命名空間爲自定義控件提供適當的起點。同樣的道理,讀者應瞭解一些來自WebControl類的常見屬性,它們可爲控件自動繼承。表2列舉了這些屬性。
屬性 | 數據類型 | 說明 |
BackColor | Color | 獲取或設置Web服務器控件的背景色。 |
BorderColor | Color | 獲取或設置Web控件的邊框顏色。 |
BorderStyle | BorderStyle | 獲取或設置Web服務器控件的邊框樣式。 |
BorderWidth | Unit | 獲取或設置Web服務器控件的邊框寬度。 |
ControlStyle | Style | 獲取Web服務器控件的樣式。 |
CssClass | String | 獲取或設置由Web服務器控件在客戶端呈現的級聯樣式表(CSS)類。 |
Enabled | Bool | 獲取或設置一個值,該值指示是否啓用Web服務器控件。 |
EnableTheming | bool | 獲取或設置一個值,該值指示是否對此控件應用主題。(asp.net 2.0新增) |
Font | FontInfo | 獲取與Web服務器控件關聯的字體屬性。 |
ForeColor | Color | 獲取或設置Web服務器控件的前景色(通常是文本顏色)。 |
Height | Unit | 服務器控件高度 |
Width | Unit | 服務器控件寬度 |
SkinID | string | 獲取或設置要應用於控件的外觀。(asp.net 2.0新增) |
3) 與屬性相關的設計時元數據
創建服務器控件是爲了提高應用開發效率,每個控件開發者都希望自己創建出的控件能夠像.NET框架中的內置標準服務器控件那樣功能強大且易於使用。例如,當控件應用者在設計界面點擊控件時,可能會希望某些屬性能夠高亮顯示,某些屬性能夠顯示在屬性瀏覽器中等等。如何才能使控件具有這樣的功能呢?這就需要在代碼中加入相關的設計時支持代碼。
實際上,實現設計時元數據是一個比較複雜的內容。然而,作爲初學者而言,我們沒有必要掌握得過於深入,下面筆者只講解一些常見的與屬性相關的設計時元數據設置。如下所示代碼,列舉了一些與屬性相關的設計時元數據設置和簡要說明。
· Bindable
這個特性表示屬性是否可以綁定一個有效數據源。通常使用布爾值進行設置,例如:Bindable(true)。如果使用值true標記屬性,表示該屬性可以綁定一個有效數據源,且應引發該屬性的屬性更改通知;如果屬性值爲false,則表示該屬性不能綁定數據。
· Browsable
指定屬性是否應該在屬性瀏覽器中顯示,使用布爾值設置。通常情況下,公用屬性和那些希望在屬性瀏覽器中顯示的屬性被設置爲Browsable(true),只讀屬性和那些不希望在屬性瀏覽器中見到的屬性被設置爲Browsable(false)。
· Category
指定屬性在屬性瀏覽器中進行分組顯示的類別。該設計時特性幫助可視化編輯器將屬性進行邏輯分組。通常分爲:外觀(Appearance)、行爲(Behavior)、佈局(Layout)、數據(Data)、操作(Action)、鍵盤(Key)、鼠標(Mouse)等。除此之外,讀者還可以自定義分類,例如Category("ItemStyle"),表示該屬性在屬性瀏覽器中顯示爲ItemStyle一組。
· Description
指定顯示在屬性瀏覽器下方,屬性的文字說明。例如:Description("this is a property")。
以上內容是實現屬性過程中最爲常見的設計時元數據設置。無論對於簡單屬性,還是複雜屬性都應該根據需要設置。
· DesignerSerializationVisibility
指定屬性是否以及如何在代碼中序列化,其值爲DesignerSerializationVisibility的枚舉值。存在三種設置方式:
(1)DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),指定序列化程序不應該序列化屬性的值;
(2)DesignerSerializationVisibility(DesignerSerializationVisibility.Visible),指定應該允許序列化程序序列化屬性的值;
(3)DesignerSerializationVisibility(DesignerSerializationVisibility.Content),指定序列化程序應該序列化屬性的內容,而不是屬性本身。此字段爲只讀。需要注意的是:沒有DesignerSerializationVisibility特性的成員將被視爲具有值爲DesignerSerializationVisibility.Visible的DesignerSerializationVisibility特性。如果可能,序列化程序會將標記爲Visible的屬性值序列化爲該類型。
· NotifyParentProperty
指示當此特性應用到的屬性的值被修改時將通知其父屬性。換言之,如果屬性的父屬性應該在該屬性值更改時接到通知,則向該屬性應用NotifyParentProperty特性。通常使用布爾值進行設置。例如,Size屬性具有兩個嵌套的子屬性:Width和Height。那麼屬性Width和Height就應標記爲NotifyParentPropertyAttribute(true),以便當屬性值更改時,它們可以通知父屬性來更新其值並顯示。
· ParseChildren
使用該特性指示當在頁上以聲明方式使用控件時,嵌套在服務器控件標記內的XML元素是應該視爲屬性還是應視爲子控件。通常情況下,包含兩種聲明方式:(1)ParseChildren(true),表示將子XML元素作爲服務器控件的屬性分析,ParseChildren(false),表示將子XML元素作爲服務器控件的子控件分析;(2)ParseChildren(bool childrenasProperty , string defaultProperty),其中childrenasPropety和方式1中的布爾值參數意義相同,defaultProperty定義默認情況下將子控件分析爲的服務器控件的集合屬性。
· PersistChildren
該特性指示設計時是否應將服務器控件的子控件作爲內部嵌套控件保持。如果該特性爲PersistChildren(true),則將服務器控件的子控件作爲嵌套服務器控件標記保持。如果爲PersistChildren(false),則將該控件的屬性作爲嵌套元素保持。
· PersistenceMode
指定如何將服務器控件屬性或事件保持到ASP.NET頁的元數據屬性。共存在4種枚舉設置方式:
(1)PersistenceMode(PersistenceMode.Attribute),指定屬性或事件保持爲特性;
(2)PersistenceMode(PersistenceMode.EncodedInnerDefaultProperty),指定屬性作爲服務器控件的唯一內部文本而。屬性值是HTML編碼的。只能對字符串做這種指定;
(3)PersistenceMode(PersistenceMode.InnerDefaultProperty),指定屬性在服務器控件中保持爲內部文本。還指示將該屬性定義爲元素的默認屬性。只能指定一個屬性爲默認屬性;
(4)PersistenceMode(PersistenceMode.InnerProperty),指定屬性在服務器控件中保持爲嵌套標記。這通常用於複雜對象;它們具有自己的持久性屬性;
· DefaultProperty
指定服務器控件的默認屬性。例如:[DefaultProperty("MyProperty")]。
· TypeConverter
指定用作此特性所綁定到的對象的轉換器的類型。用於轉換的類必須從TypeConverter繼承。使用ConverterTypeName屬性來獲取爲該特性所綁定到的對象提供數據轉換的類名。
2. 簡單屬性實現方法
在前面的幾篇文章中已經介紹了一些簡單屬性的實現方法。從中可以發現創建簡單屬性可以使用私有變量、視圖狀態和控件狀態等。在此,筆者無意對這些內容進行重複。感興趣的讀者可參閱有關文章。本節僅對實現簡單屬性的過程進行總結,並通過一個實現簡單枚舉屬性的示例加以說明。示例代碼如下所示:
// 定義枚舉 public enum BookType{ NotDefined = 0, Fiction = 1, NonFiction = 2 } // 實現屬性BookType[Bindable(true),Category("Appearance"),DefaultValue(BookType.NotDefined),Description("Fiction or Not"),] public virtual BookType BookType{ get { object t = ViewState["BookType"]; return (t == null) ? BookType.NotDefined : (BookType)t; } set { ViewState["BookType"] = value; } } |
以上代碼實現了一個枚舉BookType(包括3個枚舉值)和一個類型爲BookType的屬性BookType。根據前文所述基本概念可知,BookType是一個簡單屬性。同時,該屬性將屬性值存儲在視圖狀態ViewState中。通過這個實例,我們基本可以總結出簡單屬性的實現方法:
(1)判斷所要聲明的屬性是否是通用形式屬性;
(2)判斷所要聲明的屬性所封裝的屬性值是否是簡單數值類型、String還是枚舉類型等;
(3)如果步驟1和2都爲真,則判定所要聲明的屬性是簡單屬性;
(4)聲明該屬性的設計時特性;
(5)根據屬性的設計需求,編寫讀寫訪問器代碼;
3. 小結
本文介紹了利用ASP.NET 2.0技術,爲自定義服務器控件創建簡單屬性的內容。隨着讀者對自定義服務器控件開發的逐步理解將會發現,實現簡單屬性是構建控件過程中較爲簡單,也是較爲常見的實現內容。在創建過程中,讀者必須瞭解使用私有變量、控件狀態和視圖狀態的不同之處。這樣才能又快又好的實現簡單屬性。