asp.net控件開發基礎(14)

作者: Clingingboy  來源: 博客園  發布時間: 2010-10-02 19:50  閱讀: 1115 次  推薦: 0   原文鏈接   [收藏]  

  1.錯誤的代碼,無法解析

  首先來看一段簡單的代碼

 正確
            
<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>
            錯誤
            
<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新增的一個控件,這個頁面發生兩個錯誤,如下圖

  運行此頁面后則會報錯,出現以下提示

 

  分析器錯誤

  這里有一個問題,.net提供我們控件時,我們已經形成一種定向思維,控件就是那樣寫的,如DropDownList,其中只能是套<asp:ListItem>的,那我為什么就不能套別的屬性呢?Wizard控件為什么就要加一個WizardSteps屬性才可以正常運行呢?當我們思考到這里,我們就該尋找答案.

  2.從ParseChildren元數據屬性講起

  從第五篇開始,我們多次用到了ParseChildren此特性.還請大家先看MSDN對其的解釋,其有三種情況

  (1)ParseChildren(true)     第5篇我們使用集合屬性的時候我們曾經這樣定義,如下代碼

   [ParseChildren(true)]
    
public class Custom: Control
    
{
    }

  (2)ParseChildren(true,"<Default Property>") 第10篇當我們定義集合屬性時,我們曾這樣定義

  DropItemList為集合屬性

   [ParseChildren(true"DropItemList")]
   
public class DropColor:WebControl
    
{
   }

  (3)ParseChildren(false)  這個我們沒用過,也是我們要講的內容,當其內部定義為flase時,那么放在此控件內的元素將被解析成控件,應該說是頁分析器ControlBuilder 類.這里大家可以看看MSDN文檔對ControlBuilder 類的解釋,至少要先知道這一點。默認情況下,頁上的每個控件都與一個默認的 ControlBuilder 類關聯。 

  下面我們慢慢看下來.

  3.控件與集合屬性

  讓我們再次回憶一下ParseChildren的用法,本次的示例代碼取自asp.net2.0揭密

  (1) ParseChildren(true,"<Default Property>")的使用,此控件實現效果為隨機顯示一個內部控件內容 。RItem為一個繼承Control的控件,其內部未實現任何東西,你可以在其控件內部輸出呈現,記得上面說的ControlBuilder 類默認關聯
示例一

    [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
    
{

    }

  頁面代碼

    <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>
    

  效果就不說了,隨機顯示ritem控件的內容,注意以上控件定義了一個Items集合屬性,另外改進的話就是我們第十篇的講的,為Ritem定義屬性,作為一個集合屬性,這里就不再列出代碼.

  (1)ParseChildren(false)的使用

  此控件未添加屬性,而多了一個方法AddParsedSubObject(),控件有默認的頁面分析邏輯,重寫AddParsedSubObject方法,可以向控件添加子控件

示例二

   [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
    
{
    }

  頁面代碼

<custom:ContentRotator
        
id="ContentRotator1"
        Runat="server">
        <custom:Content
            
id="Content1"
            Runat="server">
            顯示的第一項,此不為屬性    
        
</custom:Content>    
        
<custom:Content
            
id="Content2"
            Runat="server">
            顯示的第二項,此不為屬性
            
<asp:Calendar
                
id="Calendar1"
                Runat="server" />    
        
</custom:Content>    
        
<custom:Content
            
id="Content3"
            Runat="server">
            顯示的第三項,此不為屬性  
        
</custom:Content>  
    
</custom:ContentRotator>

  注意:ContentRotator無任何屬性(其內部添加的為控件),而是用AddParsedSubObject 方法向控件添加了子控件,而不像ItemRotator控件一樣,其內部是屬性而非控件.

  4.修改默認解析邏輯

  上面已經說過每個控件都有默認的解析邏輯,其通過ControlBuilder 類來實現,可以通過重寫其方法來自定義解析邏輯.下面通過一個例子來說明,它把一個控件以自定義標簽所代替,以下列出部分代碼

示例三

    //自定義頁分析器
    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 方法  獲取與子標記對應的控件類型的 Type在此方法中,其以tab標簽代替了ServerTab控件,改寫了頁分析邏輯ControlBuilder類常用的還有AllowWhitespaceLiterals 方法 其指定控件之間是否允許存在空白,大家可以重寫此方法,然后測試下就明白了。

 

  (2)定義一個簡單的ServerTab控件。還須在父控件中重寫AddParsedSubObject方法將ServerTab控件添加到子控件中

        protected override void AddParsedSubObject(object obj)
        
{
            
if (obj is ServerTab)
                
base.AddParsedSubObject(obj);
        }

  (3)最后還需要把控件生成器跟控件關聯起來,當然還要設置ParseChildren(false)

    [ControlBuilder(typeof(ServerTabsBuilder))]
    [ParseChildren(
false)]
    
public class ServerTabs : WebControl, IPostBackEventHandler
    
{
    }

  好了,這里主要代碼就實現了,呈現代碼大家可在后面下載,下面看下頁面代碼

<%--以上省略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標簽,而非<custom:ServerTabs></custom:ServerTabs>,但實現效果是一樣的,只是我們改了默認的頁分析邏輯,自定義了控件頁生成器(分析器)。看下效果(當重新編譯后需要重新啟動vs2005才能看到效果)

  好了,這次的主題也講完了,這里需要注意的是asp.net2.0中復合控件只需要繼承CompositeControl類即可。

上一篇:asp.net控件開發基礎(13)

下一篇:asp.net控件開發基礎(15)
0
0
 
 
 

文章列表

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()