在前面的系列文章中,筆者已經列舉了幾個實現自訂伺服器控制項的樣本。通過這些樣本,讀者初步接觸了有關建立伺服器控制項屬性的內容。例如,使用私人變數、檢視狀態、控制項狀態等實現屬性等等。雖然讀者通過這些內容可以瞭解實現屬性的一些基本知識,但是這還是不夠的。從本節開始,將針對實現自訂伺服器控制項屬性的問題展開講解。本節重點介紹實現自訂伺服器控制項屬性的一些基本概念和簡單屬性的基本實現方法等內容。
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技術,為自訂伺服器控制項建立簡單屬性的內容。隨著讀者對自訂伺服器控制項開發的逐步理解將會發現,實現簡單屬性是構建控制項過程中較為簡單,也是較為常見的實現內容。在建立過程中,讀者必須瞭解使用私人變數、控制項狀態和檢視狀態的不同之處。這樣才能又快又好的實現簡單屬性。
出處:天極網