上一篇讨论了为服务器控件添加客户端功能,这一篇我们所要讲的是控件生成器
ASP.NET控件开发之控件生成器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﹥
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
Wizard为asp.net2.0新增的一个控件,这个页面发生两个错误,如下图
运行此页面后则会报错,出现以下提示
ASP.NET控件开发之控件生成器之分析器错误
这里有一个问题,.net提供我们控件时,我们已经形成一种定向思维,控件就是那样写的,如DropDownList,其中只能是套﹤asp:ListItem﹥的,那我为什么就不能套别的属性呢?Wizard控件为什么就要加一个WizardSteps属性才可以正常运行呢?当我们思考到这里,我们就该寻找答案.
ASP.NET控件开发之控件生成器2.从ParseChildren元数据属性讲起
从第五篇开始,我们多次用到了ParseChildren此特性.还请大家先看MSDN对其的解释,其有三种情况
(1)ParseChildren(true) 第5篇我们使用集合属性的时候我们曾经这样定义,如下代码
[ParseChildren(true)]
public class Custom: Control
{
}
- 1.
- 2.
- 3.
- 4.
(2)ParseChildren(true,"﹤Default Property﹥") 第10篇当我们定义集合属性时,我们曾这样定义
DropItemList为集合属性
[ParseChildren(true, "DropItemList")]
public class DropColor:WebControl
{
}
- 1.
- 2.
- 3.
- 4.
(3)ParseChildren(false) 这个我们没用过,也是我们要讲的内容,当其内部定义为flase时,那么放在此控件内的元素将被解析成控件,应该说是页分析器ControlBuilder 类.这里大家可以看看MSDN文档对ControlBuilder 类的解释,至少要先知道这一点
默认情况下,页上的每个控件都与一个默认的 ControlBuilder 类关联。
下面我们慢慢看下来.
ASP.NET控件开发之控件生成器3.控件与集合属性
让我们再次回忆一下ParseChildren的用法,本次的示例代码取自asp.net2.0揭密
(1)ParseChildren(true,"﹤Default Property﹥")的使用
此控件实现效果为随机显示一个内部控件内容
RItem为一个继承Control的控件,其内部未实现任何东西,你可以在其控件内部输出呈现,记得上面说的ControlBuilder 类默认关联
ASP.NET控件开发之控件生成器示例一
[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
{
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
ASP.NET控件开发之控件生成器页面代码
﹤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﹥
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
效果就不说了,随机显示ritem控件的内容,注意以上控件定义了一个Items集合属性
另外改进的话就是我们第十篇的讲的,为Ritem定义属性,作为一个集合属性,这里就不再列出代码.
(1)ParseChildren(false)的使用
此控件未添加属性,而多了一个方法AddParsedSubObject()
控件有默认的页面分析逻辑,重写AddParsedSubObject方法,可以向控件添加子控件
ASP.NET控件开发之控件生成器示例二
[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
{
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
ASP.NET控件开发之控件生成器页面代码
﹤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﹥
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
注意:ContentRotator无任何属性(其内部添加的为控件),而是用AddParsedSubObject 方法向控件添加了子控件,而不像ItemRotator控件一样,其内部是属性而非控件.
ASP.NET控件开发之控件生成器4.修改默认解析逻辑
上面已经说过每个控件都有默认的解析逻辑,其通过ControlBuilder 类来实现,可以通过重写其方法来自定义解析逻辑.下面通过一个例子来说明,它把一个控件以自定义标签所代替
以下列出部分代码
ASP.NET控件开发之控件生成器示例三
//自定义页分析器
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.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
(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);
}
- 1.
- 2.
- 3.
- 4.
- 5.
(3)***还需要把控件生成器跟控件关联起来,当然还要设置ParseChildren(false)
[ControlBuilder(typeof(ServerTabsBuilder))]
[ParseChildren(false)]
public class ServerTabs : WebControl, IPostBackEventHandler
{
}
- 1.
- 2.
- 3.
- 4.
- 5.
好了,这里主要代码就实现了,呈现代码大家可在后面下载,下面看下页面代码
﹤%--以上省略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﹥
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
以上镶套代码为tab标签,而非﹤custom:ServerTabs﹥﹤/custom:ServerTabs﹥,但实现效果是一样的,只是我们改了默认的页分析逻辑,自定义了控件页生成器(分析器)看下效果(当重新编译后需要重新启动vs2005才能看到效果)
好了,这次的主题也讲完了,这里需要注意的是asp.net2.0中复合控件只需要继承CompositeControl类即可.
ASP.NET控件开发之控件生成器方面的内容那个就向你介绍到这里,希望对你了解ASP.NET控件开发之控件生成器有所帮助。
【编辑推荐】