WebForm页面生命周期WEBFORM_ASPNET控件树的生成和作用

  • 摘要

  页面类是如何结合后台文件类生成整个页面的HTML的代码和后台输出的代码输出到浏览器中呢?这就牵扯到Asp.net页面生命周期中一个很重要的概念控件树。服务器以反射的方式创建了页面类对象

  • 内容

  我们可以把页面控件树理解为DOM树。先是一个HTML->HEAD-BODY-FORM......等等这些节点。DOM 树之所以可以包含子节点,是因为他们都有一个属性叫ChildNodes,用来保存当前节点的子节点们,也就是说每个节点都有一个集合。同理,控件树也必须有一个集合来包含子控件,我们看看他们的属性。

public class webform1_aspx : WebForm1, IRequiresSessionState, IHttpHandler
public class WebForm1 : Page
public class Page : TemplateControl, IHttpHandler
public abstract class TemplateControl : Control, INamingContainer, IFilterResolutionService
public class Control : IComponent, IDisposable, IParserAccessor, IUrlResolutionService, IDataBindingsAccessor, IControlBuilderAccessor, IControlDesignerAccessor, IExpressionsAccessor
{
// Fields
private string _cachedPredictableID;
private string _cachedUniqueID;
private ControlCollection _controls;
private ControlState _controlState;
private EventHandlerList _events;
private string _id;
private Control _namingContainer;
private OccasionalFields _occasionalFields;
internal Page _page;
..............
}

从他们的继承关系来看,我们可以把页面类看一个控件,因为他继承了Control类,Control类里面有一个很重要的属性叫ControlCollection,它用来包含子控件。
继承关系:页面类->后台文件类->Page->TemplateControl->Control.

我们再来看看页面类的代码:

public class webform1_aspx : WebForm1, IRequiresSessionState, IHttpHandler
{
// Fields
private static object __fileDependencies;
private static bool __initialized; // Methods
[DebuggerNonUserCode]
public webform1_aspx();
[DebuggerNonUserCode]
private LiteralControl __BuildControl__control2();
[DebuggerNonUserCode]
private HtmlHead __BuildControl__control3();
[DebuggerNonUserCode]
private HtmlTitle __BuildControl__control4();
[DebuggerNonUserCode]
private LiteralControl __BuildControl__control5();
[DebuggerNonUserCode]
private LiteralControl __BuildControl__control6();
[DebuggerNonUserCode]
private HtmlForm __BuildControlform1();
[DebuggerNonUserCode]
private void __BuildControlTree(webform1_aspx __ctrl);
[DebuggerNonUserCode]
private HtmlInputText __BuildControltxtName();
private void __Renderform1(HtmlTextWriter __w, Control parameterContainer);
[DebuggerNonUserCode]
protected override void FrameworkInitialize();
[DebuggerNonUserCode]
public override int GetTypeHashCode();
[DebuggerNonUserCode]
public override void ProcessRequest(HttpContext context); // Properties
protected HttpApplication ApplicationInstance { get; }
protected DefaultProfile Profile { get; }
}

简单说一下IRequiresSessionState是用来标记此页面可以访问Session, IHttpHandler作用是:浏览器每发送一个请求到服务器上,服务器为了处理这个请求而必须实现的一个方法叫ProcessRequest。
我们从上面的代码中,先看第一个方法private LiteralControl __BuildControl__control2()

   private LiteralControl __BuildControl__control2()
{
LiteralControl __ctrl = new LiteralControl("\r\n\r\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\r\n\r\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\r\n");
__ctrl.SetTraceData(typeof(TraceData), new TraceData(0x72, 0xae, true));
return __ctrl;
}

__BuildControl__control2() 这个方法其实就是将下面的东东添加到控件集合里面去

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">

他们他们不涉及任何的服务器操作,所以直接把他们当作文字控件来处理,节省开销。接下来的方法是__BuildControl__control3(),它返回的是一个HtmlHead,由此我们也可以推出此方法是创建Head节点的,Head节点里面还包含了一个<title>利用__BuildControl__control4()方法创建Title节点,并调用AddParsedSubObject(Control ctrl)方法将节点添加进来。所有的子控件都是调用这个方法被添加到父节点里面去的。

[DebuggerNonUserCode]
private HtmlHead __BuildControl__control3()
{
HtmlHead __ctrl = new HtmlHead("head");
HtmlTitle __ctrl1 = this.__BuildControl__control4();
IParserAccessor __parser = __ctrl;
__parser.AddParsedSubObject(__ctrl1);
__ctrl.SetTraceData(typeof(TraceData), new TraceData(0x120, 0x33, false));
return __ctrl;
}
[DebuggerNonUserCode]
private HtmlTitle __BuildControl__control4()
{
HtmlTitle __ctrl = new HtmlTitle();
__ctrl.SetTraceData(typeof(TraceData), new TraceData(0x13b, 15, false));
return __ctrl;
}

再看下一个方法就是__BuildControl__control5(),<body>标签也没有涉及到任何服务器的操作,所以也直接当作文字控件被添加进来了。

[DebuggerNonUserCode]
private LiteralControl __BuildControl__control5()
{
LiteralControl __ctrl = new LiteralControl("\r\n<body>\r\n ");
__ctrl.SetTraceData(typeof(TraceData), new TraceData(0x153, 14, true));
return __ctrl;
}

接下来就是Form标签,它标记了runat="server",所以它用了专门的一个方法_BuildControlform1()来创建它

[DebuggerNonUserCode]
private HtmlForm __BuildControlform1()
{
HtmlForm __ctrl = new HtmlForm();
base.form1 = __ctrl;
__ctrl.ID = "form1";
HtmlInputText __ctrl1 = this.__BuildControltxtName();
IParserAccessor __parser = __ctrl;
__parser.AddParsedSubObject(__ctrl1);
__ctrl.SetRenderMethodDelegate(new RenderMethod(this.__Renderform1));
__ctrl.SetTraceData(typeof(TraceData), new TraceData(0x161, 0x153, false));
return __ctrl;
}

this.__BuildControltxtName()这个方法就是用来创建<input type="text" id="txtName" runat="server" />这个控件的,来看代码。

[DebuggerNonUserCode]
private HtmlInputText __BuildControltxtName()
{
HtmlInputText __ctrl = new HtmlInputText();
base.txtName = __ctrl;
((IAttributeAccessor) __ctrl).SetAttribute("type", "text");
__ctrl.ID = "txtName";
__ctrl.SetTraceData(typeof(TraceData), new TraceData(0x20f, 0x31, false));
return __ctrl;
}

我们前面说了,凡是带有runat="server"的标记,都会在后台文件类里面声明为一个变量,此方法先创建一个input控件,然后再还给base.txtName。__ctrl.SetRenderMethodDelegate(new RenderMethod(this.__Renderform1))这一行代码比较重要。它把Renderform1这个方法追加到RenderMethod这个委托里面去,固名思义,就是追加到呈现方法的委托里面去,我们页面类控件都有一个Render(呈现)方法,通过遍历控件树,调用Render方法,将生成的HTML页面代码呈现给浏览器。我们看看__Renderform1这个方法

private void __Renderform1(HtmlTextWriter __w, Control parameterContainer)
{
base.BeginRenderTracing(__w, new TraceData("/WebForm1.aspx", 0x181, 10, true));
__w.Write(" \r\n\r\n ");
base.EndRenderTracing(__w, null);
base.BeginRenderTracing(__w, new TraceData("/WebForm1.aspx", 0x18b, 0x7a, false));
for (int i = 0; i < 5; i++)
{
base.Response.Write(i + base.Hello() + "</br>");
}
base.EndRenderTracing(__w, null);
parameterContainer.Controls[0].RenderControl(__w);
base.BeginRenderTracing(__w, new TraceData("/WebForm1.aspx", 0x240, 0x31, true));
__w.Write("\r\n <input type=\"text\" id=\"txtPwd\" />\r\n ");
base.EndRenderTracing(__w, null);
base.BeginRenderTracing(__w, new TraceData("/WebForm1.aspx", 0x271, 13, false));
__w.Write(base.strHello);
base.EndRenderTracing(__w, null);
base.BeginRenderTracing(__w, new TraceData("/WebForm1.aspx", 0x27e, 8, true));
__w.Write("\r\n ");
base.EndRenderTracing(__w, null);
base.BeginRenderTracing(__w, new TraceData("/WebForm1.aspx", 0x286, 0x1f, false));
base.Response.Write(base.strHello);
base.EndRenderTracing(__w, null);
}

RenderTracing方法是呈现跟踪,标示呈现的过程。<input type="text" id="txtName" runat="server" /> 之外,剩下的Form里面的子控件都在这个方法里面找到了痕迹。 <%=strHello%>被解析为 __w.Write(base.strHello); 页面类中的<% Response.Write(strHello); %>其实是调用了父类中的Response.Write(),Response.Write()之所以可以输出到浏览器上,原理还是HtmlTextWriter.Write()。也就是说 __w.Write(base.strHello)与Response.Write()方法是一样的,推出<%=strHello%> 等价于Response.Write()。

现在还有最后一个本章中最为重要的一个方法 __BuildControlTree()方法。页面类中的所有子控件就是通过这个方法构建成一棵控件树的

[DebuggerNonUserCode]
private void __BuildControlTree(webform1_aspx __ctrl)
{
this.InitializeCulture();
LiteralControl __ctrl1 = this.__BuildControl__control2();
IParserAccessor __parser = __ctrl;
__parser.AddParsedSubObject(__ctrl1);
HtmlHead __ctrl2 = this.__BuildControl__control3();
__parser.AddParsedSubObject(__ctrl2);
LiteralControl __ctrl3 = this.__BuildControl__control5();
__parser.AddParsedSubObject(__ctrl3);
HtmlForm __ctrl4 = this.__BuildControlform1();
__parser.AddParsedSubObject(__ctrl4);
LiteralControl __ctrl5 = this.__BuildControl__control6();
__parser.AddParsedSubObject(__ctrl5);
}

此方法把页面类对象以参数形式传进来,逐个的将子控件添加进来,this.__BuildControl__control6();其实就是后面的三个结束标签, </form></body></html>。前面已经把所有东西都创建好了,也添加到了页面类对象中去了,唯独就少了这三个结束标签,再以代码来证明刚刚的假设

[DebuggerNonUserCode]
private LiteralControl __BuildControl__control6()
{
LiteralControl __ctrl = new LiteralControl("\r\n</body>\r\n</html>\r\n");
__ctrl.SetTraceData(typeof(TraceData), new TraceData(0x2b4, 20, true));
return __ctrl;
}

Asp.net控件生成HTML代码的过程我已经记录完毕,下次我来说说服务器处理整个流程包括页面生命周期

海阔平鱼跃,天高任我行,给我一片蓝天,让我自由翱翔。
 

WebForm页面生命周期WEBFORM_ASPNET控件树的生成和作用的更多相关文章

  1. Asp.net页面生命周期详解任我行(2)-WebForm页面生命周期WEBFORM_ASPNET控件树的生成和作用

    摘要 页面类是如何结合后台文件类生成整个页面的HTML的代码和后台输出的代码输出到浏览器中呢?这就牵扯到Asp.net页面生命周期中一个很重要的概念控件树.服务器以反射的方式创建了页面类对象 内容 我 ...

  2. ASP.NET页面生命周期与控件生命周期

    ASP.NET页面生命周期 (1)PreInit 预初始化(2)Init 初始化(3)InitComplete 初始化完成(4)PreLoad 预加载(5)Load 加载(6)LoadComplete ...

  3. ASP.Net请求处理机制初步探索之旅 - Part 4 WebForm页面生命周期

    开篇:上一篇我们了解了所谓的请求处理管道,在众多的事件中微软开放了19个重要的事件给我们,我们可以注入一些自定义的业务逻辑实现应用的个性化设计.本篇,我们来看看WebForm模式下的页面生命周期. ( ...

  4. ASP.NET -- WebForm -- 页面生命周期事件

    ASP.NET -- WebForm --  页面生命周期事件在页生命周期的每个阶段中,页将引发可运行您自己的代码进行处理的事件. 1. PreInit: 使用该事件来执行下列操作: 检查 IsPos ...

  5. ASP.NET -- WebForm -- 页面生命周期

    ASP.NET -- WebForm --  页面生命周期 ASP.NET 页运行时,此页将经历一个生命周期,在生命周期中将执行一系列处理步骤.这些步骤包括初始化.实例化控件.还原和维护状态.运行事件 ...

  6. WebForm页面生命周期及asp.net运行机制

    1.先上几张原理图着重理解: 现在针对第四副图原理进行解析: 流程: 1.浏览器发送请求 2.服务器软件(IIS)接收,它最终的目的就是为了向客户输出它请求的动态页面生成的html代码. 3.服务器不 ...

  7. 再学习Webform页面生命周期

    参考文章: 在vs2010,新建一个aspx页面,页面头部有一行代码: <%@ Page Language="C#" AutoEventWireup="true&q ...

  8. (转)Asp.net页面生命周期详解任我行(1)-小试牛刀,编写页面代码

    原文地址:http://www.cnblogs.com/xuyubing/archive/2013/10/01/3348344.html 前言 很久很久以前,还是我在学校的时候,我就看了传智里面视频, ...

  9. Asp.net页面生命周期详解任我行(1)-小试牛刀,编写页面代码

    前言 很久很久以前,还是我在学校的时候,我就看了传智里面视频,学习了一下Asp.net页面生命周期,当时看的时候,因为内功不够深厚,看起来很吃力,现在回头温习了一下,还是有点收获的,于是想用博客记录一 ...

随机推荐

  1. mac_开启ftp并访问

    [启动&关闭] mac下一般用smb服务来进行远程文件访问,但要用FTP的话,高版本的mac os默认关掉了,可以用如下命令打开: sudo -s launchctl load -w /Sys ...

  2. English is very important!

    Well, as a college student,I haven't realized how important the English is . But as a web programmer ...

  3. Code Forces 414B 很不错的双手,以促进合规

    http://codeforces.com/problemset/problem/414/B 题目挺不错的.留个纪念,活动脑筋不错的题目 #include<iostream> #inclu ...

  4. oracle_constraint的用处

    ql中constraint主要是增加约束 这个主要就是增加约束的 以下几种约束 .并 一一列举: 1.主键约束: 主键约束:就是对一个列进行了约束,约束为(非空.不重复)要对一个列加主键约束的话,这列 ...

  5. [cocos2d-x 3.0] 触摸显示器

    一.基本使用 1.首先,声明一个监听器 有两种,EventListenerTouchOneByOne 和 EventListenerTouchAllAtOnce,前者是单点触控.后者是多点触控.后者我 ...

  6. Php设计模式(三):行为型模式part1

    原文详见:http://www.ucai.cn/blogdetail/7023?mid=1&f=5 可以在线运行查看效果哦! 在上一篇我们讲了结构型模式,结构型模式是讨论类和对象的结构的.总共 ...

  7. Exception dispatching input event. use XlistView

    今天上午解决Bug,一个上午的时间: log: 11-01 14:49:14.826: E/InputEventReceiver(30810): Exception dispatching input ...

  8. java设计模式之四建造者模式(Builder)

    工厂类模式提供的是创建单个类的模式,而建造者模式则是将各种产品集中起来进行管理,用来创建复合对象,所谓复合对象就是指某个类具有不同的属性,其实建造者模式就是前面抽象工厂模式和最后的Test结合起来得到 ...

  9. Java清理临时目录文件Demo(一)

    /** * 删除单个文件 * * @param sPath * 被删除文件的文件名 * @return 单个文件删除成功返回true,否则返回false */ public static boolea ...

  10. 清除css、javascript及背景图在浏览器中的缓存

    在实际项目开发过过程中,页面是上传到服务器上的.而为了减少服务器的压力,让用户少加载,浏览器会将图片.css.js缓存到本地中,以便下次访问网站时使用.这样做不仅减少了服务器的压力,并且也减少了用户的 ...