ASP.NET控件開(kāi)發(fā)之控件生成器淺析
上一篇討論了為服務(wù)器控件添加客戶端功能,這一篇我們所要講的是控件生成器
ASP.NET控件開(kāi)發(fā)之控件生成器1.錯(cuò)誤的代碼,無(wú)法解析
首先來(lái)看一段簡(jiǎn)單的代碼
- 正確
- ﹤asp:Wizard ID="Wizard1" runat="server"﹥
- ﹤WizardSteps﹥
- ﹤asp:WizardStep ID="WizardStep1" runat="server" Title="Step 1"﹥
- 21212﹤/asp:WizardStep﹥
- ﹤asp:WizardStep ID="WizardStep2" runat="server" Title="Step 2"﹥
- ﹤/asp:WizardStep﹥
- ﹤/WizardSteps﹥
- ﹤/asp:Wizard﹥
- 錯(cuò)誤
- ﹤asp:Wizard ID="Wizard2" runat="server"﹥
- ﹤asp:WizardStep ID="WizardStep1" runat="server" Title="Step 1"﹥
- 21212﹤/asp:WizardStep﹥
- ﹤asp:WizardStep ID="WizardStep2" runat="server" Title="Step 2"﹥
- ﹤/asp:WizardStep﹥
- ﹤/asp:Wizard﹥
- ﹤br /﹥
- ﹤br /﹥
- ﹤asp:Label ID="Label1" runat="server" Text="Label"﹥
- ﹤asp:TextBox ID="TextBox2" runat="server"﹥﹤/asp:TextBox﹥
- ﹤/asp:Label﹥
- ﹤br /﹥
- ﹤asp:TextBox ID="TextBox3" runat="server"﹥12345﹤/asp:TextBox﹥
- ﹤br /﹥
- ﹤asp:Label ID="Label2" runat="server" Text="Label"﹥12345﹤/asp:Label﹥
- ﹤br /﹥
- ﹤br /﹥
- ﹤asp:TextBox ID="TextBox1" runat="server"﹥
- ﹤asp:Label runat="server" Text="Label"﹥﹤/asp:Label﹥
- ﹤/asp:TextBox﹥
Wizard為asp.net2.0新增的一個(gè)控件,這個(gè)頁(yè)面發(fā)生兩個(gè)錯(cuò)誤,如下圖
運(yùn)行此頁(yè)面后則會(huì)報(bào)錯(cuò),出現(xiàn)以下提示
ASP.NET控件開(kāi)發(fā)之控件生成器之分析器錯(cuò)誤
這里有一個(gè)問(wèn)題,.net提供我們控件時(shí),我們已經(jīng)形成一種定向思維,控件就是那樣寫的,如DropDownList,其中只能是套﹤asp:ListItem﹥的,那我為什么就不能套別的屬性呢?Wizard控件為什么就要加一個(gè)WizardSteps屬性才可以正常運(yùn)行呢?當(dāng)我們思考到這里,我們就該尋找答案.
ASP.NET控件開(kāi)發(fā)之控件生成器2.從ParseChildren元數(shù)據(jù)屬性講起
從第五篇開(kāi)始,我們多次用到了ParseChildren此特性.還請(qǐng)大家先看MSDN對(duì)其的解釋,其有三種情況
(1)ParseChildren(true) 第5篇我們使用集合屬性的時(shí)候我們?cè)?jīng)這樣定義,如下代碼
- [ParseChildren(true)]
- public class Custom: Control
- {
- }
(2)ParseChildren(true,"﹤Default Property﹥") 第10篇當(dāng)我們定義集合屬性時(shí),我們?cè)@樣定義
DropItemList為集合屬性
- [ParseChildren(true, "DropItemList")]
- public class DropColor:WebControl
- {
- }
(3)ParseChildren(false) 這個(gè)我們沒(méi)用過(guò),也是我們要講的內(nèi)容,當(dāng)其內(nèi)部定義為flase時(shí),那么放在此控件內(nèi)的元素將被解析成控件,應(yīng)該說(shuō)是頁(yè)分析器ControlBuilder 類.這里大家可以看看MSDN文檔對(duì)ControlBuilder 類的解釋,至少要先知道這一點(diǎn)
默認(rèn)情況下,頁(yè)上的每個(gè)控件都與一個(gè)默認(rèn)的 ControlBuilder 類關(guān)聯(lián)。
下面我們慢慢看下來(lái).
ASP.NET控件開(kāi)發(fā)之控件生成器3.控件與集合屬性
讓我們?cè)俅位貞浺幌翽arseChildren的用法,本次的示例代碼取自asp.net2.0揭密
(1)ParseChildren(true,"﹤Default Property﹥")的使用
此控件實(shí)現(xiàn)效果為隨機(jī)顯示一個(gè)內(nèi)部控件內(nèi)容
RItem為一個(gè)繼承Control的控件,其內(nèi)部未實(shí)現(xiàn)任何東西,你可以在其控件內(nèi)部輸出呈現(xiàn),記得上面說(shuō)的ControlBuilder 類默認(rèn)關(guān)聯(lián)
ASP.NET控件開(kāi)發(fā)之控件生成器示例一
- [ParseChildren(true, "Items")]
- public class ItemRotator : CompositeControl
- {
- private ArrayList _items = new ArrayList();
- [Browsable(false)]
- public ArrayList Items
- {
- get { return _items; }
- }
- protected override void CreateChildControls()
- {
- Random rnd = new Random();
- int index = rnd.Next(_items.Count);
- Control item = (Control)_items[index];
- this.Controls.Add(item);
- }
- }
- public class RItem : Control
- {
- }
ASP.NET控件開(kāi)發(fā)之控件生成器頁(yè)面代碼
- ﹤custom:ItemRotator
- id="ItemRotator1"
- Runat="server"﹥
- ﹤custom:ritem ID="Item1" runat="server"﹥
- First Item
- ﹤/custom:ritem﹥
- ﹤custom:ritem ID="Item2" runat="server"﹥
- Second Item
- ﹤asp:Calendar
- id="Calendar1"
- Runat="server" /﹥
- ﹤/custom:ritem﹥
- ﹤custom:ritem ID="Item3" runat="server"﹥
- Third Item
- ﹤/custom:ritem﹥
- ﹤/custom:ItemRotator﹥
效果就不說(shuō)了,隨機(jī)顯示ritem控件的內(nèi)容,注意以上控件定義了一個(gè)Items集合屬性
另外改進(jìn)的話就是我們第十篇的講的,為Ritem定義屬性,作為一個(gè)集合屬性,這里就不再列出代碼.
(1)ParseChildren(false)的使用
此控件未添加屬性,而多了一個(gè)方法AddParsedSubObject()
控件有默認(rèn)的頁(yè)面分析邏輯,重寫AddParsedSubObject方法,可以向控件添加子控件
ASP.NET控件開(kāi)發(fā)之控件生成器示例二
- [ParseChildren(false)]
- public class ContentRotator : WebControl
- {
- protected override void AddParsedSubObject(object obj)
- {
- if (obj is Content)
- base.AddParsedSubObject(obj);
- }
- protected override void RenderContents(HtmlTextWriter writer)
- {
- Random rnd = new Random();
- int index = rnd.Next(this.Controls.Count);
- this.Controls[index].RenderControl(writer);
- }
- }
- [
- ToolboxItem(false)
- ]
- public class Content : Control
- {
- }
ASP.NET控件開(kāi)發(fā)之控件生成器頁(yè)面代碼
- ﹤custom:ContentRotator
- id="ContentRotator1"
- Runat="server"﹥
- ﹤custom:Content
- id="Content1"
- Runat="server"﹥
- 顯示的***項(xiàng),此不為屬性
- ﹤/custom:Content﹥
- ﹤custom:Content
- id="Content2"
- Runat="server"﹥
- 顯示的第二項(xiàng),此不為屬性
- ﹤asp:Calendar
- id="Calendar1"
- Runat="server" /﹥
- ﹤/custom:Content﹥
- ﹤custom:Content
- id="Content3"
- Runat="server"﹥
- 顯示的第三項(xiàng),此不為屬性
- ﹤/custom:Content﹥
- ﹤/custom:ContentRotator﹥
注意:ContentRotator無(wú)任何屬性(其內(nèi)部添加的為控件),而是用AddParsedSubObject 方法向控件添加了子控件,而不像ItemRotator控件一樣,其內(nèi)部是屬性而非控件.
ASP.NET控件開(kāi)發(fā)之控件生成器4.修改默認(rèn)解析邏輯
上面已經(jīng)說(shuō)過(guò)每個(gè)控件都有默認(rèn)的解析邏輯,其通過(guò)ControlBuilder 類來(lái)實(shí)現(xiàn),可以通過(guò)重寫其方法來(lái)自定義解析邏輯.下面通過(guò)一個(gè)例子來(lái)說(shuō)明,它把一個(gè)控件以自定義標(biāo)簽所代替
以下列出部分代碼
ASP.NET控件開(kāi)發(fā)之控件生成器示例三
- //自定義頁(yè)分析器
- public class ServerTabsBuilder : ControlBuilder
- {
- public override Type GetChildControlType(string tagName, IDictionary attribs)
- {
- if (String.Compare(tagName, "tab", true) == 0)
- return typeof(ServerTab);
- else
- return null;
- }
- }
- [ToolboxItem(false)]
- public class ServerTab : Control
- {
- private string _Text;
- public string Text
- {
- get { return _Text; }
- set { _Text = value; }
- }
- }
(1)ServerTabsBuilder類重寫了ControlBuilder類的
GetChildControlType 方法 獲取與子標(biāo)記對(duì)應(yīng)的控件類型的 Type
在此方法中,其以tab標(biāo)簽代替了ServerTab控件,改寫了頁(yè)分析邏輯
ControlBuilder類常用的還有AllowWhitespaceLiterals 方法 其指定控件之間是否允許存在空白,大家可以重寫此方法,然后測(cè)試下就明白了
(2)定義一個(gè)簡(jiǎn)單的ServerTab控件.
還須在父控件中重寫AddParsedSubObject方法將ServerTab控件添加到子控件中
- protected override void AddParsedSubObject(object obj)
- {
- if (obj is ServerTab)
- base.AddParsedSubObject(obj);
- }
(3)***還需要把控件生成器跟控件關(guān)聯(lián)起來(lái),當(dāng)然還要設(shè)置ParseChildren(false)
- [ControlBuilder(typeof(ServerTabsBuilder))]
- [ParseChildren(false)]
- public class ServerTabs : WebControl, IPostBackEventHandler
- {
- }
好了,這里主要代碼就實(shí)現(xiàn)了,呈現(xiàn)代碼大家可在后面下載,下面看下頁(yè)面代碼
- ﹤%--以上省略css代碼--%﹥
- ﹤custom:ServerTabs
- ID="ServerTabs1"
- Runat="Server"﹥
- ﹤tab Text="First Tab"﹥
- ﹤asp:Label ID="Label1" runat="server" Text="Label"﹥﹤/asp:Label﹥
- Contents of the first tab
- ﹤/tab﹥
- ﹤tab Text="Second Tab"﹥
- Contents of the second tab
- ﹤/tab﹥
- ﹤tab Text="Third Tab"﹥
- Contents of the third tab
- ﹤/tab﹥
- ﹤/custom:ServerTabs﹥
以上鑲套代碼為tab標(biāo)簽,而非﹤custom:ServerTabs﹥﹤/custom:ServerTabs﹥,但實(shí)現(xiàn)效果是一樣的,只是我們改了默認(rèn)的頁(yè)分析邏輯,自定義了控件頁(yè)生成器(分析器)看下效果(當(dāng)重新編譯后需要重新啟動(dòng)vs2005才能看到效果)
好了,這次的主題也講完了,這里需要注意的是asp.net2.0中復(fù)合控件只需要繼承CompositeControl類即可.
ASP.NET控件開(kāi)發(fā)之控件生成器方面的內(nèi)容那個(gè)就向你介紹到這里,希望對(duì)你了解ASP.NET控件開(kāi)發(fā)之控件生成器有所幫助。
【編輯推薦】