自定义控件的构建(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揭秘》