Page类的派生关系
Page是从TemplateControl中派生的,TemplateControl从Control派生。他们的定义分别如下:
//Control,从object派生,实现了四个接口
public class Control : System.ComponentModel.IComponent,
System.IDisposable,
System.Web.UI.IParserAccessor,
System.Web.UI.IDataBindingsAccessor
{
}
//TemplateControl从Control派生,实现了接口System.Web.UI.INamingContainer
public abstract class TemplateControl : Control, System.Web.UI.INamingContainer
{
}
//Page从TemplateControl派生,实现了接口System.Web.UI. IHttpHandler
public class Page : TemplateControl, System.Web.IHttpHandler
{
}
而你编写的Page,你在_aspx.cs文件中编写的类是从Page派生,这个继承关系是你添加WebForm页面时,Visual Studio .net帮你建好的。而aspx的页面在运行时会被解释为一个从_aspx.cs文件中的类的派生类。(这里需要补充资料)。
正 题
猜想
当IIS接收到aspx页面一个请求,交给aspnet_isapi.dll处理。aspnet_isapi然后做以下的事情:
MyPage __p;
__p = new MyPage();
__p.ProcessRequest(System.Web.HttpContext.Current)
以上是我个人的估计,究竟事实是不是这样,我会找Microsoft的工程师要答案!我在System.Web.dll中没有找到处理产生Page实例的il,Page类的实例的创建可能是aspnet_isapi.dll作了,而aspnet_isapi.dll不是使用.net编写的,其内部的运行究竟如何无从得知。
以下不是猜想!
ProcessRequest(HttpContext)方法
Page中的ProcessRequest(System.Web.HttpContext)方法是这样的:
public virtual void ProcessRequest(Sunrise.Web.HttpContext context)
{
this.SetIntrinsics(context); //进行最基本初始化
this.ProcessRequest(); //处理请求
}
SetIntrinsics方法
从上面的代码可以看到,首先会调用SetIntrinsics(HttpContext context)方法,SetIntrinsics的作用是对Page的成员变量进行基本的初始化。SetIntrinsics如下:
//进行最基本初始化,设置_context、_request、_application、_cache的初值
private void SetIntrinsics(HttpContext context)
{
this._context = context;
this._request = context.Request;
this._response = context.Response;
this._application = context.Application;
this._cache = context.Cache;
if(this._clientTarget != null)
{
if(this._clientTarget.Length >0)
{
this._request.ClientTarget = this._clientTarget;
}
}
//调TempalateControl的HookUpAutomaticHandlers()方法初始化基本事件
//包括:Init、Load、DataBinding、PreRender、Unload、Error、
//AbortTransaction、CommitTransaction
this.HookUpAutomaticHandlers();
}
ProcessRequest方法
然后就开始执行ProcessRequest()方法,大致如下:
try
{
if(this.IsTransacted) //如果是事务状态
{
this.ProcessRequestTransacted();
}
else //非事务状态
{
this.ProcessRequestMain();
}
this.ProcessRequestEndTrace();
}
finally
{
//释放资源,把_request、_response置为null,并执行UnloadRecursive(true)
this.ProcessRequestCleanup();
}
ProcessRequestMain方法
通过上面的代码可以知道,当一个Page是非事务模式是,响应ProcessRequestMain()。事实上,是事务模式时,也是调用ProcessRequestMain()。以下是关于ProcessRequestMain()方法的伪码:
//step1 调用Control.InitRecursive()进行递归初始化 Control的OnInit()方法将会在此时被调用
this.InitRecursive(null);
//如果是回传状态
if(this.IsPostBack)
{
//step2 装载ViewState
///装载Page的ViewState,Control的LoadViewState()方法将会在这里被调用
this.LoadPageViewState();
//step3 处理回传的数据,如果Control实现了System.Web.UI.IPostBackDataHandler,
//LoadPostData()方法在此时被调用
this.ProcessPostData(this._requestValueCollection, true);
}
//step4 调用Control.LoadRecursive()方法装载SubControls
//Control的Load()方法在此时被调用
this.LoadRecursive();
//如果是回传状态
if(this.IsPostBack)
{
//step 5 再次处理未处理完的回传数据,
//注意第二次调用时第二个参数是false,而第一次是true
//第二次处理回传数据的作用可能是用来处理在OnLoad中创建的Control的数据,??
this.ProcessPostData(this._leftoverPostData, false);
//step6 响应数据更改事件,
//如果Control实现了System.Web.UI.IPostBackDataHandler接口,
//Control的RaisePostDataChangedEvent()方法在此时被调用
this.RaiseChangedEvents();
//step7 响应回传事件 __dopostback()
//如果Control实现了System.Web.UI.IPostBackEventHandler接口,Control的RaisePostBackEvent()方法在此时执行
this.RaisePostBackEvent(this._requestValueCollection);
//step8 调用Control的PreRenderRecursiveInternal()方法,
//Control的OnPreRender()方法在此时被调用
this.PreRenderRecursiveInternal();
}
//step9 BuiltTree 构建ViewState,
//ViewState使用通过LosFormatter对ViewState进行编码,保存在Trace中
this.BuildProfileTree("ROOT",this.EnableViewState);
//step10 保存Page的ViewState
//Control的SaveViewState()方法
this.SavePageViewState();
//step11 输出
//Control的Render()方法在此时被调用
this.RenderControl(this.CreateHtmlTextWriter(this.Response.Output));
ProcessRequestMain方法图示
Init |
Load ViewState |
Load PostData |
Load |
Load PostData
|
RaiseChangeEvents
|
RaisePostBackEvents
|
BuildProfileTree
|
SaveViewState |
Render |
Dispose |
Unload |
此时产生HTML代码 |
OnInit()方法被调用 |
OnLoad()方法被调用 |
处理回传数据 |
再次处理回传数据 |
响应数据修改事件,如TextBox的TextChagned |
响应回传事件,客户端的__dopostback |
ProcessRequestTransacted方法
事实上,在事务状态下,也是调用ProcessRequestMain()的,我们来看一下ProcessRequestTransacted的代码:
bool V_0;
System.Web.Util.TransactedCallback V_1;
V_0 = false;
//创建事务回调的delegate
V_1 = new System.Web.Util.TransactedCallback(this.ProcessRequestMain);
//在事务环境下调用ProcessRequestMain()
System.Web.Util.Transactions.InvokeTransacted(
V_1,
(System.EnterpriseServices.TransactionOption)(this._transactionMode),
ref V_0
);
if(V_0)
{
this.OnAbortTransaction(System.EventArgs.Empty); //终止事务
}
else
{
this.OnCommitTransaction(System.EventArgs.Empty); //提交事务
}
InitRecursive方法
在ProcessRequestMain 方法中,首先执行Control的InitRecursive方法。在InitRecursive中,OnInit方法被执行。具体如下:
internal void InitRecursive(System.Web.UI.Control namingContainer) //ok
{
string V_0;
int V_1;
int V_2;
System.Web.UI.Control V_3;
if(this._controls != null)
{
//flag[128]表示是否实现了System.Web.UI.INamingContainer接口
if(this.flags[128])
{
namingContainer = this;
}
//设置_controls为只读,并返回原来的_readOnlyErrorMsg,保存在V_0
V_0 = this._controls.SetCollectionReadOnly("Parent_collections_readonly");
V_1 = this._controls.Count;
for(V_2 = 0;V_2 < V_1; V_2++)
{
V_3 = this._controls[V_2];
V_3._namingContainer = namingContainer;
if(namingContainer != null)
{
if((V_3._id == null)
&&
(!(V_3.flags[64]))
)
{
this.GenerateAutomaticID();
}
}
V_3._page = this._page;
V_3.InitRecursive(namingContainer);
}
//回复_controls原来的状态
this._controls.SetCollectionReadOnly(V_0);
this._controlState = Sunrise.Web.UI.ControlState.Initialized;
//OnInit方法在此时被调用
this.OnInit(System.EventArgs.Empty);
this.TrackViewState();
}
}
LoadPageViewState方法
在ProcessRequestMain 方法中,执行InitRecursive方法进行初始化后,如果Page的IsPostBack属性值为True,则会接着执行LoadPageViewState方法。
LoadPageViewState应该结合来SavePageViewState来看,这样更容易理解。具体如下:
internal void LoadPageViewState()
{
System.Web.UI.Triplet V_0;
string V_1;
//获得使用LosFormater反序列化(Deserialize)得到的对象
V_0 = (System.Web.UI.Triplet)this.LoadPageStateFromPersistenceMedium();
if(V_0 != null)
{
V_1 = (string)V_0.First;
int.Parse(V_1,System.Globalization.NumberFormatInfo.InvariantInfo);
this.GetTypeHashCode();
//判断V_1和Page调用GetTypeHashCode()方法获得的值是否相等,
//并把比较结果保存在_fPageLayoutChanged ??
this._fPageLayoutChanged = (int.Parse(V_1,System.Globalization.NumberFormatInfo.InvariantInfo) != this.GetTypeHashCode());
if(!(this._fPageLayoutChanged))
{
//调用Control.LoadViewStateRecursive()方法,
//递归装载ViewState,
//Control的LoadViewState()方法将会在这里被执行
this.LoadViewStateRecursive(V_0.Second);
this._controlsRequiringPostBack = (System.Collections.ArrayList)V_0.Third;
}
}
}
LoadViewStateRecursive方法
通过观察LoadPageViewState的代码可以得知,LoadPageViewState中执行LoadViewStateRecursive来进行Control的LoadViewState过程。
LoadViewStateRecursive的过程大致是这样,把参数savedState转换为Triplet对象,使用Triplet对象的First做参数来执行LoadView方法,然后使用Triplet对象的Second和Third对Controls进行LoadViewStateRecursive。
这个方法应该参照SaveViewStateRecursive一起阅读,这样更方便理解。如下:
internal void LoadViewStateRecursive(object savedState)
{
System.Web.UI.Triplet V_0;
System.Collections.ArrayList V_1;
System.Collections.ArrayList V_2;
Sunrise.Web.UI.ControlCollection V_3;
int V_4;
int V_5;
int V_6;
int V_7;
//如果参数为null或EnableViewState为False
if((savedState == null)
|| (this.flags[4]) //flags[4]表示EnableViewState,true时,EnableViewState为false,false时EnableViewState为true
)
{
return;
}
//转换为Triplet对象,Triplet有三个public的Fields:First、Second、Third,使用Triplet表示使代码更直观,而且更快
V_0 = (System.Web.UI.Triplet)savedState;
//如果control的Page不为null,而且this.Page.IsPostBack为True,执行LoadViewState方法
if((this.Page != null)
&& (this.Page.IsPostBack)
)
{
this.LoadViewState(V_0.First);
}
//对this.Controls中的Control进行LoadViewState
if(V_0.Second != null)
{
V_1 = (System.Collections.ArrayList)V_0.Second; //kes
V_2 = (System.Collections.ArrayList)V_0.Third; //values
V_3 = this.Controls;
V_4 = V_3.Count;
V_5 = V_1.Count;
for(V_6=0; V_6 < V_5; V_6 ++)
{
V_7 = (int)V_1[V_6];
if(V_7 < V_4)
{
V_3[V_7].LoadViewStateRecursive(V_2[V_6]);
}
else
{
if(this._controlsViewState == null)
{
this._controlsViewState = new System.Collections.Hashtable();
}
this._controlsViewState[V_7] = V_2[V_6];
}
}
}
//将_controlState设置为ViewStateLoaded
this._controlState = Sunrise.Web.UI.ControlState.ViewStateLoaded;
}
LoadViewState方法
LoadViewState方法的是Protected,当你构建自己的Control时,可以重载它。此时你应该在你写的LoadViewState方法里执行base. LoadViewState(something)。Control的LoadViewState代码如下:
protected virtual void LoadViewState(object savedState)
{
object V_0;
if(savedState != null)
{
this.ViewState.LoadViewState(savedState);
V_0 = this.ViewState["Visible"];
if(V_0 != null)
{
// flags[16]表示Visible,false时,Visible为true,值为false时,Visible为true
this.flags[16] = (!((bool)V_0));
this.flags[32] = true; // flags[32]表示是否已经LoadView ??
}
}
}
ProcessPostData方法
当ProcessRequestMain执行了LoadPageViewState方法后,接着就是ProcessPostData,这个方法是用来处理回传数据。这个方法被执行两遍,分别在LoadRecursive之前和之后个执行一遍。第一次执行时,参数fBeforeLoad值为True,第二次为False。
//处理回传的数据
//当fBeforeLoad为true时,是第一次调用,fBeforeLoad为false时,为第二次调用
private void ProcessPostData(System.Collections.Specialized.NameValueCollection postData, bool fBeforeLoad) //ok
{
string V_0;
Sunrise.Web.UI.Control V_1;
System.Web.UI.IPostBackDataHandler V_2;
bool V_3;
System.Collections.ArrayList V_4;
string V_5;
System.Web.UI.IPostBackDataHandler V_6;
bool V_7;
System.Collections.IEnumerator V_8;
System.IDisposable V_9;
if(this._changedPostDataConsumers == null)
{
this._changedPostDataConsumers = new System.Collections.ArrayList();
}
if(postData != null)
{
V_8 = postData.GetEnumerator();
try
{
while(V_8.MoveNext())
{
V_0 = (string)V_8.Current;
if(V_0 != null)
{
//判断回传数据是否在系统PostFields内,
//s_systemPostFields包括__EVENTTARGET、__EVENTARGUMENT、__VIEWSTATE
if(!s_systemPostFields.Contains(V_0))
{
V_1 = this.FindControl(V_0); //在Page中查找匹配的Control
if((V_1 == null) //如果找不到,将数据保存在_leftoverPostData中
&& (fBeforeLoad)
)
{
if(this._leftoverPostData == null)
{
this._leftoverPostData = new System.Collections.Specialized.NameValueCollection();
}
this._leftoverPostData.Add(V_0,null);
}
else //如果找到了……
{
//如果找到的结果实现了System.Web.UI.IPostBackDataHandler接口,
//调用RegisterRequiresRaiseEvent方法
//赋值给_registeredControlThatRequireRaiseEvent
if(!(V_1 is System.Web.UI.IPostBackDataHandler))
{
if(V_1 is System.Web.UI.IPostBackEventHandler)
{
this.RegisterRequiresRaiseEvent(
(System.Web.UI.IPostBackEventHandler)V_1
);
}
}
else//如果找到的结果没有实现System.Web.UI.IPostBackDataHandler接口
{
V_2 = (System.Web.UI.IPostBackDataHandler)V_1;
V_3 = V_2.LoadPostData(V_0,this._requestValueCollection); //V_2装载回传数据
if(V_3) //如果V_2装载回传数据时发现数据已经被修改,将登记V_2在_changedPostDataConsumers中
{
this._changedPostDataConsumers.Add(V_2);
}
//在_controlsRequiringPostBack中移去V_0
//_controlsRequiringPostBack的值在LoadPageViewState()方法中被赋值
if(this._controlsRequiringPostBack != null)
{
this._controlsRequiringPostBack.Remove(V_0);
}
}
}
}
}
}
}
finally
{
V_9 = V_8 as System.IDisposable;
if(V_9 != null)
{
V_9.Dispose();
}
}
}
V_4 = null;
//处理_controlsRequiringPostBack中剩下的数据项
if(this._controlsRequiringPostBack != null)
{
V_8 = this._controlsRequiringPostBack.GetEnumerator();
try
{
while(V_8.MoveNext())
{
V_5 = (string)V_8.Current;
V_6 = (System.Web.UI.IPostBackDataHandler)this.FindControl(V_5);
if(V_6 != null)
{
//V_7装载回传数据
V_7 = V_6.LoadPostData(V_5,this._requestValueCollection);
//如果V_6装载回传数据时发现数据已经被修改,
//将登记V_6在_changedPostDataConsumers中
if(V_7) {
this._changedPostDataConsumers.Add(V_6);
}
}
else
{
if(fBeforeLoad) //如果是第一次调用,保留
{
if(V_4 == null)
{
V_4 = new System.Collections.ArrayList();
}
V_4.Add(V_5);
}
}
}
}
finally
{
V_9 = V_8 as System.IDisposable;
if(V_9 != null)
{
V_9.Dispose();
}
}
}
//如果是第一次调用,值为未处理的数据项,第二次调用值为null
this._controlsRequiringPostBack = V_4;
}
LoadRecursive方法
LoadRecursive方法的过程大致是这样,先执行Load方法,然后对Controls执行LoadRecursive。
代码如下:
internal void LoadRecursive()
{
string V_0;
int V_1;
int V_2;
//在这里执行OnLoad方法
this.OnLoad(System.EventArgs.Empty);
if(this._controls != null)
{
//设置_controls为只读
V_0 = this._controls.SetCollectionReadOnly("Parent_collections_readonly");
V_1 = this._controls.Count;
for(V_2 = 0;V_2 < V_1; V_2++)
{
this._controls[V_2].LoadRecursive();
}
//回复原来的状态
this._controls.SetCollectionReadOnly(V_0);
}
this._controlState = Sunrise.Web.UI.ControlState.Loaded;
}
RaiseChangedEvents方法
如果Control实现了System.Web.UI.IPostBackDataHandler接口,Control的RaisePostDataChangedEvent将会在这里被调用。需要的响应的RaisePostDataChangedEvent的典型例子是TextBox。TextBox的Text数据在客户端可能被修改,如果修改了,需要获得通知,以响应TextChanged事件。
internal void RaiseChangedEvents() //ok
{
int V_0;
System.Web.UI.IPostBackDataHandler V_1;
Sunrise.Web.UI.Control V_2;
if(this._changedPostDataConsumers != null)
{
for(V_0=0; V_0 < this._changedPostDataConsumers.Count; V_0++)
{
V_1 = (System.Web.UI.IPostBackDataHandler)this._changedPostDataConsumers[V_0];
V_2 = V_1 as Sunrise.Web.UI.Control;
//如果V_2是Page的SubControls,调用RaisePostDataChangedEvent()
if((V_2 != null)
||
(V_2.IsDescendentOf(this))
)
{
V_1.RaisePostDataChangedEvent();
}
}
}
}
RaisePostBackEvent方法
当执行Client端JavaScript的__dopostback()函数时,将产生回传事件。(此处需要补充资料)。回传事件的原理是,Page产生的HTML代码中,会产生两个隐藏域(Hidden),__EVENTTARGET和__ EVENTARGUMENT,不同的Control产生执行__dopostback()的方法不一致。调用的时候大多数是这样:
<input type=hidden name=__EVENTTARGET>
<input type=hidden name=__ EVENTARGUMENT>
__dopostback(control_uniqueid, ‘’);
当Form提交的时候,RaisePostBackEvent中根据control_uniqueid来找到需要响应事件的Server Control。__ EVENTARGUMENT是事件的参数,参数在开发简单的Server Control通常是不需要,在复杂的Server Control时才用。
例如System.Web.UI.WebControls.LinkButton。
private void RaisePostBackEvent(System.Collections.Specialized.NameValueCollection postData)
{
string V_0;
Sunrise.Web.UI.Control V_1;
string V_2;
if(this._registeredControlThatRequireRaiseEvent != null)
{
this.RaisePostBackEvent(_registeredControlThatRequireRaiseEvent, null);
return;
}
V_0 = postData["__EVENTTARGET"];
if((V_0 != null)
&&
(V_0.Length >0)
)
{
V_1 = this.FindControl(V_0);
if((V_1 != null)
&& (V_1 is System.Web.UI.IPostBackEventHandler)
)
{
V_2 = postData["__EVENTARGUMENT"];
this.RaisePostBackEvent((System.Web.UI.IPostBackEventHandler)V_1, V_2);
}
}
else
{
this.Validate();
}
}
PreRenderRecursiveInternal方法
Control的PrenRender方法会在这里被执行。代码如下:
internal void PreRenderRecursiveInternal()
{
string V_0;
int V_1;
int V_2;
// flags[16]表示Visible,false时,Visible为true,值为false时,Visible为true
if(!(this.flags[16]))
{
this.EnsureChildControls();
//OnPreRender在这里被执行
this.OnPreRender(System.EventArgs.Empty);
if(this._controls != null)
{
//设置只读
V_0 = this._controls.SetCollectionReadOnly("Parent_collections_readonly");
V_1 = this._controls.Count;
for(V_2 = 0;V_2 < V_1; V_2++)
{
this._controls[V_2].PreRenderRecursiveInternal();
}
//回复原来的状态
this._controls.SetCollectionReadOnly(V_0);
}
}
this._controlState = Sunrise.Web.UI.ControlState.PreRendered;
}
BuildProfileTree 方法
构建ViewState的存放空间,放在Trace里。(此处需要更详细的说明)
protected void BuildProfileTree(string parentId, bool calcViewState)
{
int V_0;
int V_1;
int V_2;
calcViewState = calcViewState || (!(this.flags[4]));
if(calcViewState)
{
//计算LosFormatter会产生编码结果的长度
V_0 = Sunrise.Web.UI.LosFormatter.EstimateSize(this.SaveViewState());
}
else
{
V_0 = 0;
}
this.Page.Trace.AddNewControl(
this.UniqueID,
parentId,
this.GetType().FullName,
V_0
);
if(this._controls != null)
{
V_1 = this._controls.Count;
for(V_2 =0; V_2 < V_1; V_2 ++)
{
this._controls[V_2].BuildProfileTree(this.UniqueID, calcViewState);
}
}
}
SavePageViewState 方法
保存Page的ViewState,LosFormatter的编码结果放置于_viewStateToPersist中。此方法应该结合LoadPageViewState一起来分析。
使用Triplet和Pair保存ViewState时常用的技巧。这里使用了Triplet。
(需要补充关于LosFormatter的说明)
SavePageViewState和SavePageStateToPersistenceMedium的代码如下:
internal void SavePageViewState()
{
System.Web.UI.Triplet V_0;
int V_1;
if(!(this._needToPersistViewState))
{
return;
}
V_0 = new System.Web.UI.Triplet();
V_1 = this.GetTypeHashCode();
//将数字转换为字符
V_0.First = V_1.ToString(System.Globalization.NumberFormatInfo.InvariantInfo);
//_registeredControlsThatRequirePostBack是一个ArrayList,
//其内容项 RegisterRequiresPostBack(System.Web.UI.Control control)来添加
V_0.Third = this._registeredControlsThatRequirePostBack;
if(this.Context.TraceIsEnabled)
{
this.Trace.AddControlViewstateSize(
this.UniqueID,
Sunrise.Web.UI.LosFormatter.EstimateSize(V_0)
);
}
//执行SaveViewStateRecursive()方法,把返回结果保存赋给V_0.Second。
V_0.Second = this.SaveViewStateRecursive();
this.SavePageStateToPersistenceMedium(V_0);
}
protected virtual void SavePageStateToPersistenceMedium(object viewState)
{
this._viewStateToPersist = viewState;
}
SaveViewStateRecursive方法
在SavePageViewState方法中执行SaveViewStateRecursive方法来获取ControlTree的SaveViewState的结果。
internal object SaveViewStateRecursive()
{
object V_0;
System.Collections.ArrayList V_1;
System.Collections.ArrayList V_2;
int V_3;
int V_4;
Sunrise.Web.UI.Control V_5;
object V_6;
System.Web.UI.Triplet V_7;
if(this.flags[4])
{
return(null);
}
//获得Control本身的SaveViewState()结果
V_0 = this.SaveViewState();
V_1 = null;
V_2 = null;
//获取SubControls的SaveViewStateRecursive()结果
if(this._controls != null)
{
V_3 = this._controls.Count;
for(V_4=0; V_4<V_3; V_4++)
{
V_5 = this._controls[V_4];
V_6 = V_5.SaveViewStateRecursive();
if(V_6 != null)
{
if(V_1 == null)
{
V_1 = new System.Collections.ArrayList();
V_2 = new System.Collections.ArrayList();
V_1.Add(V_4);
V_2.Add(V_6);
}
}
}
}
V_7 = null;
//如果Control本身的SaveViewState()结果不为null,
//而且SuControls的SaveViewStateRecursive()结果不为null
if((V_0 != null)
|| (V_1 != null)
)
{
V_7 = new System.Web.UI.Triplet(V_0, V_1, V_2);
}
return(V_7);
}
RenderControl方法
ProcessRequestMain()执行了PreRenderRecursive后,接着就执行RenderControl方法。RenderControl是在Control中定义的方法。RenderControl是执行Control的Render方法,输出html文本。
public void RenderControl(System.Web.UI.HtmlTextWriter writer) //ok
{
System.Web.HttpContext V_0;
int V_1;
int V_2;
// flags[16]表示Visible,false时,Visible为true,值为false时,Visible为true
if(!(this.flags[16]))
{
//如果this._page不为null,……
V_0 = (this._page == null) ? null: this._page._context;
if(V_0 != null)
{
if(V_0.TraceIsEnabled)
{
V_1 =V_0.Response.GetBufferedLength();
//Render方法在这里被执行
this.Render(writer);
V_2 = V_0.Response.GetBufferedLength();
V_0.Trace.AddControlSize(this.UniqueID, V_2 - V_1);
}
}
else
{
//Render方法在这里被执行
this.Render(writer);
}
}
}
Render和RenderChildren
Render和RenderChildren都可以被重载。在System.Web.UI.WebControls命名空间里,大部分Control都是从System.Web.UI.WebControls.WebControl中派生的,WebControl重载Render方法,分拆成三个方法,RenderBeginTage、RenderContent和RenderEndTag。如果Cotnrol是从WebControl中派生,通常只需要重载RenderContent。
下面是Control中的代码:
protected virtual void Render(System.Web.UI.HtmlTextWriter writer)
{
this.RenderChildren(writer);
}
protected virtual void RenderChildren(System.Web.UI.HtmlTextWriter writer) //ok
{
int V_0;
int V_1;
if(this._renderMethod != null)
{
this._renderMethod(writer,this);
}
else
{
if(this._controls != null)
{
V_0 = this._controls.Count;
for(V_1=0; V_1<V_0; V_1 ++)
{
this._controls[V_1].RenderControl(writer);
}