今天写demo的时候,居然出现这样的错误:
Parser Error Message: Type 'ServerControl_CachePanel.CachePanel' does not have a public property named 'WebUserControl1'.
静下心来想了一会,发面它可能和自定义
控件中的ParseChildren好像有关系.
如果我们在一个textbox
控件中嵌入一个label
控件的话:
Code
<asp:TextBox ID="TextBox1" runat="server">
<asp:Label runat="server" Text="Label"></asp:Label>
</asp:TextBox>
页面会显示错误信息,asp:TextBox的Text属性不允许子对象,不能通过调试,这显然属于分析器错误 但是你可以这样写:
Code
<asp:DropDownList ID="DropDownList1" runat="server">
<asp:ListItem>1</asp:ListItem>
<asp:ListItem>2</asp:ListItem>
<asp:ListItem>3</asp:ListItem>
</asp:DropDownList>
为什么有的
控件中可以嵌入其它的标记而有的
控件又不行呢.查看了MSDN,才发现其中的原理.
MSDN:
1:在开发ASP.NET 服务器
控件时,ParseChildrenAttribute 类指示页分析器应如何处理页上声明的服务器
控件标记中嵌套的内容.
2:ParseChildrenAttribute 类允许您以 ParseChildrenAttribute 元数据属性标记服务器
控件来为自定义服务器
控件指定分析逻辑。
3:以元数据属性 (Attribute) ParseChildren(true) 标记服务器
控件将指示分析器把包含在服务器
控件标记内的元素解释为属性 (Property)。
4:以元数据属性 (Attribute) ParseChildren(true,"<Default Property>") 标记服务器
控件将把 DefaultProperty 属性 (Property) 设置为传递到该属性 (Attribute) 的属性 (Property) 名称。
5:以元数据属性 ParseChildren(false)(默认值)标记服务器
控件将指示分析器把包含在服务器
控件标记中的元素解释为将通过关联的 ControlBuilder 进行分析的内容,即解释为
控件。
MSDN分别针对应用ParseChildren(true)和ParseChildren(false)给了个demo.具体例子,这里我就不帖了.结论是这样的:
1:在应用了[ParseChildren(true]元数据属性,产生的属性最终会赋值给CollectionPropertyControl的某个属性中。
2:在应用了[ParseChildren(false]元数据属性,产生的
控件对象加入到CollectionPropertyControl的Controls集合中.
ParseChildren(false)的使用: 我们平时还可以这样使用ParseChildren(false)
第一:使用默认的页面分析逻辑
Code
[ParseChildren(false)]
public class ContentClass : WebControl
{
protected override void AddParsedSubObject(object obj)
{
if (obj is Content)
base.AddParsedSubObject(obj);
}
protected override void RenderContents(HtmlTextWriter writer)
{
//加载
控件 }
}
//子
控件 public class Content : Control
{
//省略代码
}
页面代码如下:
Code
<cc1:ContentClass
Runat="server">
<cc1:Content
id="Content1"
Runat="server">
显示的第一项,此不为属性
</cc1:Content>
</cc1:ContentClass>
控件有默认的页面分析逻辑,重写AddParsedSubObject方法,可以向
控件添加子
控件,也可以不重AddParsedSubObject方法,这样的情况适合加载外部
控件以及用户
控件.
第二:重写默认的页面分析逻辑
每个
控件都有默认的解析逻辑,其通过ControlBuilder 类来实现,可以通过重写其方法来自定义解析逻辑.
Code
//自定义分析器
public class CustomControlBuilder : ControlBuilder
{
public override Type GetChildControlType(string tagName, IDictionary attribs)
{
if (String.Compare(tagName, "content", true) == 0)
return typeof(customControl);
else
return null;
}
}
//定义一个简单的
控件 public class customControl : Control
{
//代码省略
}
第一步:CustomControlBuilder类重写了ControlBuilder类的GetChildControlType 方法 获取与子标记对应的
控件类型的 Type在此方法中,其以content标签代替了customControl
控件,改写了页分析逻辑.
第二步:定义一个简单的customControl
控件.还须在父
控件中重写AddParsedSubObject方法将customControl
控件添加到子
控件中:
Code
protected override void AddParsedSubObject(object obj)
{
if (obj is customControl)
base.AddParsedSubObject(obj);
}
第三步:把
控件生成器跟
控件关联起来,当然还要设置ParseChildren(false)
Code
[ControlBuilder(typeof(CustomControlBuilder))]
[ParseChildren(false)]
public class webCoustomControl : WebControl
{
}
第四步:页面代码:
Code
<cc1:webCoustomControl
Runat="Server">
<content/>
</cc1:webCoustomControl>
至于ParseChildren(true)的使用情况这次就不说了,它是和
控件复杂属性相关联的。
总结:在asp.net
编程过程中,其实有很多非常小的地方我们平时因为注意的不够,往往对它们没有深入的了解,造成遇到问题的时候会出现难以解决的现象。
控件开发是一个非常有趣而且非常有意义的事情,所以有必要对它进入更深入的了解以及应用。本文如有不妥处望大家批评指教。