自定义控件的构建(8)
在前面的几节基础上,现在我们开始涉足构建对象集合的控件,以GridView而言,其内部就包含了多个DataBoundField控件来表示所要显示的各个列。
首先了解名为ParseChildren的特性,其用来决定如何解析控件包含的内容:值为True时,控件所包含的内容将作为控件的属性解析,若该控件包含子控件,
则该子控件将作为外围控件的属性进行解析;当值为False时,则控件包含的内容将独立解析,且子控件将不作为属性解析。
下面则创建在ParseChildren为Ture和False的不同情况下的一个自定义控件,其功能用于页面中随机显示内容。
[ParseChildren(false)]
public class RotatorsContentControl:WebControl{protected override void AddParsedSubObject(object obj){if (obj is Content){base.AddParsedSubObject(obj);
}}protected override void RenderContents(HtmlTextWriter writer){Random random = new Random();
int x = this.Controls.Count;int index = random.Next(x);
this.Controls[0].RenderControl(writer);
}}
public class Content:Control{}
上面的代码中实际包含了2个控件,Content和RotatorsContentControl控件,后者从其子控件中随机选择一个Content控件并呈现在浏览器中,
注意这里的ParseChildren值为False,如果未添加该属性,Content控件将被当做RotatorsContentControl的一个属性来解析,这样会产生一个异常。
演示的关键代码:
<myControl:RotatorsContentControl ID="RotatorsContentControl1" runat="server"><myControl:Content ID="Content1" runat="server">This is an apple!</myControl:Content><myControl:Content ID="Content2" runat="server">This is an apple,too!<asp:Button ID="Button1" runat="server" Text="Button" /></myControl:Content><myControl:Content ID="Content3" runat="server">This is a banana,too!</myControl:Content></myControl:RotatorsContentControl>如果ParseChildren的值为True,则要为控件添加一个引用子控件的属性。
[ParseChildren(true,"Items")]public class ItemControl : Control{private ArrayList array = new ArrayList();[Browsable(false)]
public ArrayList Items
{get { return array; }}protected override void CreateChildControls(){Random random = new Random();
int index = random.Next(array.Count);
Control item = (Control)array[index];this.Controls.Add(item);
}}public class Item : Control{}
ParseChildren的第二个参数是控件属性的名字,上面的代码设计了一个Items属性表示控件所包含的控件项。与第一个示例不同的是,这里ItemRotator控件
内所包含的控件不会自动的解析成子控件,在CreatChildControl()运行后,该控件仅包含一个子控件
演示:
<myControl:ItemControl ID="ItemControl1" runat="server"><myControl:Item ID="Item1" runat="server">A</myControl:Item><myControl:Item ID="Item2" runat="server">B</myControl:Item><myControl:Item ID="Item3" runat="server">C</myControl:Item></myControl:ItemControl>事实上,控件的内容可不必解析成控件,在创建表示项集合的控件时,也可以把项表示成对象。
public class Images{public string Url{get;set;}public string Text{get;
set;
}}[ParseChildren(true, "Items")]public class ImageRotator : WebControl{private ArrayList array = new ArrayList();[Browsable(false)]
public ArrayList Items
{get { return array; }}protected override void RenderContents(HtmlTextWriter writer){if (array.Count > 0)
{Random random = new Random();
Images image =(Images) array[random.Next(array.Count)];writer.AddAttribute(HtmlTextWriterAttribute.Src, image.Url);writer.AddAttribute(HtmlTextWriterAttribute.Alt, image.Text);writer.RenderBeginTag(HtmlTextWriterTag.Img);writer.RenderEndTag();}}}
注意这里的细微变化,Images仅仅是个类,并未从任何控件基类继承。可以看看界面中如何使用这个控件的
<myControl:ImageRotator ID="ImageRotator1" runat="server"><myControl:Images Text="image1" /><myControl:Images Text="image2" /><myControl:Images Text="image3" /></myControl:ImageRotator>将页面的Trace打开,可以发现其中的ImageRotator1中并未包含任何子控件
本文参考了《ASP.NET 3.5揭秘》