constructor -> AddParsedSubObject -> ...
可见 AddParsedSubObject 这个方法会较早被调用。
System.Web.UI.Control 类实现了 IParserAccessor 接口,
它对此接口实现如下:(通过 Reflector 看到的)
void IParserAccessor.AddParsedSubObject(object obj)
{
this.AddParsedSubObject(obj);
}
protected virtual void AddParsedSubObject(object obj)
{
Control control1 = obj as Control;
if (control1 != null)
{
this.Controls.Add(control1);
}
}
{
this.AddParsedSubObject(obj);
}
protected virtual void AddParsedSubObject(object obj)
{
Control control1 = obj as Control;
if (control1 != null)
{
this.Controls.Add(control1);
}
}
我们可以看到 Control 类给 AddParsedSubObject 方法提供了一个默认实现,默认的行为就是简单的判断如果该对象存在则添加到自己的子控件集合中去。
同时他设定访问性级别为 virtual,给继承自他的子类(我们要编写的自定义控件)以重写该方法的实现的机会。
在某些高级的页面模版解决方案中,通常覆盖这个方法,把分析出来的页面的控件添加到某个特定的页面模版中去。
Paul Wilson 的 MasterPage 控件里这个部分是这样写的:
protected override void AddParsedSubObject(object obj) {
if (obj is Wilson.MasterPages.ContentRegion) {
this.contents.Add(obj);
}
else {
this.defaults.Controls.Add((Control)obj);
}
}
if (obj is Wilson.MasterPages.ContentRegion) {
this.contents.Add(obj);
}
else {
this.defaults.Controls.Add((Control)obj);
}
}
下面看一下 msdn 对该接口的解释。
IParserAccessor 接口只规定了一个方法:
void AddParsedSubObject(object obj);
这个方法的目的是:(中文 msdn 这个方法的翻译很烂,郁闷了很久之后翻看原文的才看懂了)。
通知服务器控件,它的一个元素(XML 或 HTML) 已经分析完毕了;并且把这个元素添加到服务器控件的 ControlCollection 对象中去。
参数 obj: 已分析的 Object.
注:
除非你覆盖它,这个方法会自动的向控件的 ControlCollection 集合(通过 Control.Controls 来访问)添加一些 LiteralControl.(实际上是 tag 间隔处的空白)。
msdn 例子:
这个代码演示了如何把自定义的子 tag (例子中叫做 "myitem") 当作 TextBox 来处理。
// Custom ControlBuilder class. Interprets nested tag name "myitem" as a textbox.
public class MyControlBuilder : ControlBuilder
{
public override Type GetChildControlType(String tagName,
IDictionary attributes)
{
if (String.Compare(tagName, "myitem", true) == 0)
{
return typeof(TextBox);
}
return null;
}
}
[
ControlBuilderAttribute(typeof(MyControlBuilder))
]
public class MyControl : Control
{
// Store all the controls specified as nested tags.
private ArrayList items = new ArrayList();
// This function is internally invoked by IParserAccessor.AddParsedSubObject(Object).
protected override void AddParsedSubObject(Object obj)
{
if (obj is TextBox)
{
items.Add(obj);
}
}
// Override 'CreateChildControls'.
protected override void CreateChildControls()
{
System.Collections.IEnumerator myEnumerator = items.GetEnumerator();
while(myEnumerator.MoveNext())
this.Controls.Add((TextBox)myEnumerator.Current);
}
}
public class MyControlBuilder : ControlBuilder
{
public override Type GetChildControlType(String tagName,
IDictionary attributes)
{
if (String.Compare(tagName, "myitem", true) == 0)
{
return typeof(TextBox);
}
return null;
}
}
[
ControlBuilderAttribute(typeof(MyControlBuilder))
]
public class MyControl : Control
{
// Store all the controls specified as nested tags.
private ArrayList items = new ArrayList();
// This function is internally invoked by IParserAccessor.AddParsedSubObject(Object).
protected override void AddParsedSubObject(Object obj)
{
if (obj is TextBox)
{
items.Add(obj);
}
}
// Override 'CreateChildControls'.
protected override void CreateChildControls()
{
System.Collections.IEnumerator myEnumerator = items.GetEnumerator();
while(myEnumerator.MoveNext())
this.Controls.Add((TextBox)myEnumerator.Current);
}
}
题外话:
刚才不小心搜到孟子E章在 csdn 文档中心写的一个关于 ASP.NET 1.x 和 2.0 对照的文章,里面提到 IParserAccessor 接口的以及这个方法好像被微软封掉了。以后只能是系统才有权调用了。
虽然说 ASP.NET 2.0 加入了 MasterPage 机制,但这样做搞的 1.1 的代码不兼容了岂不是很霸道?哪位清楚详情的请证实一下这个事情。
参考:
Master Page, Paul Wilson 相关:http://authors.aspalliance.com/paulwilson/Articles/?id=14