.net控件开发(五)之 深入理解控件的呈现原理
首言 :
ASP.NET控件基本上都是继承Framework 已有三个基类,Control,WebControl,CompositeControl下面我就各个基类的呈现方法
讲述 Control,WebControl, CompositeControl 各自的呈现过程。
第一个: Control 呈现过程。
在 Control 所继承的控件的输出流程:
在正常的控件呈现输出 ( 就是说不是 ajax 控件里 , 在 ajax 会打乱此图 ) 中,它是一个循环调用的过程,看看下面的图就知道了 。
现在来分析分析其实现过程,在 Render 方法中调用另外一个名为 RenderChildren 的受保护成员,
该方法接收服务器控件内容的 HtmlTextWriter 对象 .
{
this .RenderChildren(writer);
}
{
/*
在这里this.occasionalFields中,它实现了OccasionalFields类,此类是一个sealed类,也就是一个不可继承的类,在其类中有一个Controls的public属性,返回的是一个控件集(ControlCollection)
在此处是用于维护其子控件列表的集合容器。
*/
ICollection children = ( this ._occasionalFields == null ) ? null : ((ICollection) this ._occasionalFields.Controls);
this .RenderChildrenInternal(writer, children);
}
在此,我们什么时候给了 this._occasionalFields 赋值了呢。赋了什么值呢。当加入到控件树上时(使用了 findControl 查找控件),它会调用一个
private void EnsureNamedControlsTable
方法(这个方法在 findControl 中调用)去确保所有控件都被正确加载完成。
然后将其填充在一个控件集中
this .FillNamedControlsTable( this , this ._occasionalFields.Controls);,
从这里开始注意了, Ajax 异步回调与正常输出的控件是从这里开始分岐的。
1 internal void RenderChildrenInternal(HtmlTextWriter writer, ICollection children)
2 {
3 /*
4 this.RareFields如果设置这个参数,意谓着以自定义的方式去改写RenderChildern
5 没有的话,将进行默态的流程对所有的子控件进行处理。
6
7 */
8 if (( this .RareFields != null ) && ( this .RareFields.RenderMethod != null ))
9 {
10 /* 调用RenderMethod委托,Asp.net Ajax在使用Control.SetRenderMethodDelegate时,对应的回调函数就是在此时处理的
11 关于ajax的控件程现流程详见: http://www.cnblogs.com/liuxu-wxy/archive/2007/04/25/727346.html
12
13 */
14 writer.BeginRender();
15 this .RareFields.RenderMethod(writer, this );
16 writer.EndRender();
17 }
18 else if (children != null )
19 {
20 // 如果不设置这个RareFieldsEnsured,会把所有的控件呈现
21 // 依次调用Control里所有子控件的RenderControl
22 foreach (Control control in children)
23 {
24 control.RenderControl(writer); // 完成子控件的呈现过程
25 }
26 }
27 }
28
接下来就是真正呈现过程的入口方法
// 该方法为入口方法
public virtual void RenderControl(HtmlTextWriter writer)
{
this .RenderControl(writer, this .Adapter);
}
下面这段代码, 这个是一个过渡代码,其中的 this.flags[0x10] 没有搞明白是什么一回事,但不要紧。
它都会去调用 RenderControlInternal 方法
RenderControlInternal代码段
下面代码。控件是否有相关的呈现适配器,有的话就适配器调用适配器的相关呈现方法
private void RenderControlInternal(HtmlTextWriter writer, ControlAdapter adapter)
{
if (adapter != null )
{
// 调用相关的适配器方法
adapter.BeginRender(writer);
adapter.Render(writer);
adapter.EndRender(writer);
}
else
{
this .Render(writer);
}
}
理解就是 :
1. 控件开始呈现
2. 控件是否有相关的呈现适配器,有的话就适配器调用适配器的相关呈现方法
3. 呈现子控件
4. 完成控件呈现
第二个: WebControl 呈现过程
WebControl: 在 Control 的基础上增加了 Style ,呈现方面就是在 Render(HtmlTextWriter writer) 方法中扩展了三个呈现方法,增加一个属性呈现方法
流程图如下:
伪代码如下:
{
this .AddAttributesToRender(writer);
// 呈现Tag开始标记
}
protected override void Render(HtmlTextWriter writer)
{
// 重写了Control的Render方法并增加了三个扩展方法
this .RenderBeginTag(writer);
this .RenderContents(writer);
this .RenderEndTag(writer);
}
protected internal virtual void RenderContents(HtmlTextWriter writer)
{
// 调用Control的呈现
base .Render(writer);
}
public virtual void RenderEndTag(HtmlTextWriter writer)
{
// 呈现结束标记
}
protected virtual void AddAttributesToRender(HtmlTextWriter writer)
{
// 呈现Attribute
}
第三个: CompositeControl 呈现过程
CompositeControl 类是一个抽象类,为自定义控件提供命名容器和控件设计器功能,该自定义控件包含全部子控件或使用其他控件功能。此类由 Login 和 Wizard 等控件继承
复合控件类必须派生自 System.Web.UI.WebControls.CompositeControl 类。这一点与 ASP.NET 1.x 环境下开发复合控件有些不同。在 ASP.NET 1.x 中,复合控件必须实现 System.Web.UI.INamingContainer 接口。然而,在 ASP.NET 2.0 下,复合控件类的基类则发生了变化
CompositeControl 重写了 WebControl 的 Render(HtmlTextWriter writer) ,增加了设计时支持以创建子控件
protected internal override void Render(HtmlTextWriter writer)
{
// 如果在设计时,创建子控件,也就是在设计时增加友好体验
if (DesignMode)
this .EnsureChildControls();
base .Render(writer);
}
————————————————————————————————————
后述: