构建更复杂的控件时,需要表示对象集合。比如:DropDownList中的ListItem项,GridView中的DataBoundField项。
4.1使用ParseChildren属性
本节示例将会创建多内容滚动控件,可以随机显示HTML内容;会创建一个服务器端选项卡控件,可以生成内容的选项卡视图。
·使用ParseChildren 属性,该属性决定如何分析控件包含的内容。
当ParseChildren设置为true时,控件所包含的内容作为控件的属性进行分析。如果该空间含有子控件,那么子控件被当作外围控件的属性来分析。
当ParseChildren设置为flase时,不会把子控件当作属性分析,控件包含的内容将独立分析。
Control类的ParseChildren属性默认为flase,但是WebControl类继承并重写了该默认值为true。因此,当我们从System.Web.UI.Control继承时,默认为flase,当我们从System.Web.UI.WebControl或System.Web.UI.WebControl继承时默认为true。
代码示例:创建一个内容滚动控件,在页面随机的显示内容。创建此控件有两种方法,分别在ParseChildren为true或flase情况下。
ContentRotator.cs —— ParseChildren:flase
ItemRotator.cs——ParseChildren(true,”Items”)//第二个参数是某个属性的变量名
ImageRotator.cs——ParseChildren(true,”ImageItems”)
ContentRotator.cs控件实际上包含了两个控件:ContentRotator和Content控件。ContentRotator控件从他的子控件中随机的选择一个Content控件,并把起呈现到浏览器。
如果PareseChildren设为true,则Content控件会被作为ContentRotator控件的属性来分析,会产生异常。此时需要为控件添加一个引用所含子控件的属性。
ItemRotator控件不同于ContentRotator控件的是其所包含的子控件不会自动解析成子控件,ItemRotator通过CreateChildControls()方法来创建自己的子控件,而ContentRotator只是在向客户端RenderContent()的时候确定显示或者不显示。
ImageRotator控件中的项ImageItem并不是一个控件而是一个普通类。它仅仅表示一个属性。从开启了跟踪的页面可以查看ImageRotator控件并不包含任何子控件。
4.2使用AddParsedSubObject()方法
当ParseChildren=false时,控件内容均为控件的子控件(Controls),其中的空格回车,都会添加到Controls集合。控件内的任何非服务器端控件都会解析成Literal控件,并没有进行过滤。
AddParsedSubObject()方法在每个子控件添加到Controls集合时被调用,通过重写该方法,可以组织某种控件添加到Controls集合。
代码示例:ContentRotator.cs,判断控件是否是Content控件,是则添加到Controls集合。
Code
using System;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace JerryShi.Controls
{
[ParseChildren(false)]
public class ContentRotator : WebControl
{
protected override void AddParsedSubObject(object obj)
{
//must be Conten control,so that add to Controls collection
if (obj is Content)
{
base.AddParsedSubObject(obj);
}
}
protected override void RenderContents(HtmlTextWriter writer)
{
Random random = new Random();
int index = random.Next(this.Controls.Count);
this.Controls[index].RenderControl(writer);
}
}
public class Content : Control
{ }
}
4.3使用ControlBuilder
除AddParsedSubObject()方法外的更多控制,通过给控件关联一个自定义的ControlBuilder类来修改控件解析内容的行为。
ControlBuilder类支持的最有用的方法:
AllowWhiteSpaceLiterals()——删除控件内容两端的空白
AppendLiteralString()——删除控件内容中的所有空白
GetChildControlType()——指定某种标签解析成哪种控件,可以把任意标签映射成任意控件
代码示例:ServerTab.cs
Code
using System;
using System.Collections;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace JerryShi.Controls
{
[ControlBuilder(typeof(ServerTabsBuilder))]
[ParseChildren(false)]
public class ServerTabs:WebControl,IPostBackEventHandler
{
public int SelectedTabIndex
{
get
{
if (ViewState["SelectedTabIndex"] == null)
{
return 0;
}
else
{
return (int)(ViewState["SelectedTabIndex"]);
}
}
set
{
ViewState["SelectedTabIndex"] = value;
}
}
protected override HtmlTextWriterTag TagKey
{
get
{
return HtmlTextWriterTag.Div;
}
}
protected override void AddParsedSubObject(object obj)
{
if (obj is ServerTab)
base.AddParsedSubObject(obj);
}
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 (SelectedTabIndex == 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();// A
writer.RenderEndTag();// div
}
writer.Write("<br style='clear:both' />");
writer.AddAttribute(HtmlTextWriterAttribute.Class, "tabContents");
writer.RenderBeginTag(HtmlTextWriterTag.Div);
this.Controls[SelectedTabIndex].RenderControl(writer);
writer.RenderEndTag();
}
IPostBackEventHandler 成员#region IPostBackEventHandler 成员
public void RaisePostBackEvent(string eventArgument)
{
SelectedTabIndex = Int32.Parse(eventArgument);
}
#endregion
}
public class ServerTabsBuilder : ControlBuilder
{
public override Type GetChildControlType(string tagName, IDictionary attribs)
{
if (String.Compare(tagName, "tab", true).Equals(0))
{
return typeof(ServerTab);
}
else
{
return null;
}
}
}
public class ServerTab : Control
{
private string _Text;
public string Text
{
get { return _Text; }
set { _Text = value; }
}
}
}