zoukankan      html  css  js  c++  java
  • WebForm页面生命周期WEBFORM_ASPNET控件树的生成和作用

    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("
    
    <!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">
    ");
        __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("
    <body>
        ");
        __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("  
    
        ");
        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("
          <input type="text" id="txtPwd" />
          ");
        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("
          ");
        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("
    </body>
    </html>
    ");
        __ctrl.SetTraceData(typeof(TraceData), new TraceData(0x2b4, 20, true));
        return __ctrl;
    }
    复制代码

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

     

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

     

     

     

  • 相关阅读:
    vim编辑参数
    hive的元数据存储在mysql后,报错的解决方法!
    hadoop添加删除节点
    Android画图Path的使用
    android中path的arcTo方法的使用 .
    StrongReference、SoftReference、WeakReference、PhantomReference .
    为Android应用增加渠道信息 自动化不同渠道的打包过程
    C#知识点
    CSS判断浏览器
    调用外部程序
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3348708.html
Copyright © 2011-2022 走看看