今天写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(t