自定义控件的构建(9)

前面重点介绍了ParseChildren特性,当其为False时,控件的内容会自动的解析成控件的子控件,这时控件内包含的所有内容都会添加到Controls集合中,

而控件内任何非服务器控件将解析成Literal控件,某些时候可能仅允许一种控件被添加到Controls集合里。

AddParsedSubObject()

AddParsedSubObject()会在每个控件被添加进Controls集合中调用,通过重写该方法,可以阻止控件被添加进Controls集合。

ControlBuilder

ASP.NET框架在解析页面时,会使用到ControlBuilder类,因此可以给控件关联一个自定义的ControlBuilder类修改控件解析内容的行为,ControlBuilder类有几个比较常用的方法,可以查看MSDN,其中GetChildControlType()可以把任意标签映射成控件。

看一段比较长的代码

    [ParseChildren(false)]
    [ControlBuilder(typeof(ServerTabsBuild ))]
    public class TabControl:WebControl,IPostBackEventHandler
    {
        public int SelectTabIndex
        {
            get 
            {
                if (ViewState["SelectTabIndex"] == null)
                {
                    return 0;
                }
                else
                {
                    return (int)ViewState["SelectTabIndex"];
                }
            }
            set
            {
                ViewState["SelectTabIndex"] = value;
            }
        }
        protected override void AddParsedSubObject(object obj)
        {
            if (obj is ServerTab)
            {
                base.AddParsedSubObject(obj);
            }
        }
        protected override HtmlTextWriterTag TagKey
        {
            get { return HtmlTextWriterTag.Div; }
        }
        
        protected override void RenderContents(HtmlTextWriter writer)
        {
            for (int i = 0; i < this.Controls.Count; i++)
            {
              ServerTab tab=(ServerTab )this.Controls[i];
              string eRef = Page.ClientScript.GetPostBackClientHyperlink(this, i.ToString());
              if (SelectTabIndex == i)
              {
                  writer.AddAttribute(HtmlTextWriterAttribute.Class, "tab selectedTab");
               
              }
              else
              {
                  writer.AddAttribute(HtmlTextWriterAttribute.Class, "tab");
              }
              writer.RenderBeginTag(HtmlTextWriterTag.Div);
              writer.AddAttribute(HtmlTextWriterAttribute.Href, eRef);
              writer.RenderBeginTag(HtmlTextWriterTag.A);
              writer.Write(tab.Text);
              writer.RenderEndTag();
              writer.RenderEndTag();
            }
            writer.Write("<br style='clear:both' />");
            writer.AddAttribute(HtmlTextWriterAttribute.Class, "tabContents");
            writer.RenderBeginTag(HtmlTextWriterTag.Div);
            this.Controls[SelectTabIndex].RenderControl(writer);
            writer.RenderEndTag();
        }
        public void RaisePostBackEvent(string eventArgument)
        {
            SelectTabIndex = Int32.Parse(eventArgument);
        }
    }
    public class ServerTab : Control
    {
        public string Text { get; set; }
    }
    public class ServerTabsBuild : ControlBuilder
    {
        public override  Type  GetChildControlType(string tagName, IDictionary attribs)
        {
            if (String.Compare(tagName, "tab", true) == 0)
            {
                return typeof(ServerTab);
            }
            else
            {
                return null;
            }
        }
    }

代码比较长,但是依然可以分析其逻辑,其中TabControl类被ControlBuilder修饰了,而该特性将TabControl关联到一个称为ServerTabsBuild

的ControlBuilder类,ServerTabsBuild类则重写了GetChildControlType(),其作用是将<tab>映射成控件,也正是这个原因,在TabControl类

声明选项卡时不再需要使用runat属性了。

看看页面上的代码

 <mycustom:TabControl ID="TabControl" runat="server" >
     <tab Text="First">
      Hello!
     </tab>
      <tab Text="First">
      Hello!!
     </tab>
      <tab Text="First">
       Hello!!!
     </tab>
    </mycustom:TabControl>

可以看到<tab>标签将<custom:Tab runat=”server”/>取代了。

 

 

 

本文参考了《ASP.NET 3.5揭秘》

posted @ 2010-08-05 08:21  ringgo  阅读(545)  评论(0编辑  收藏  举报