• 一起谈.NET技术,asp.net控件开发基础(14) 狼人:


      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)
  • 相关阅读:
    C#线程同步lock,Monitor,Mutex,同步事件和等待句柄(1)
    多线程 C#解决方案小结
    10款交互设计原型开发工具
    创建自定义配置节
    禁用外键 oracle
    GUIDESIGNSTUDIO3中文帮助(1)欢迎使用 GUI Design Studio 3.0
    大数据量的数据库设计思考
    gui design studio 3 中文帮助(2)获取帮助
    NHibernate之旅(24):探索NHibernate二级缓存(下)(转)
    客户端原型GUI Design Studio
  • 原文地址:https://www.cnblogs.com/waw/p/2162814.html
Copyright © 2020-2023  润新知