• Page类与Control类的生命周期(life cycle)比较总结[转]


    最近一段时间在使用Microsoft SharePoint2007,进行开发一个Document管理系统,里面有使用SharePoint Designer设计Page布局,需要使用自定义开发的Webpart控件,由于本来就没有进行搞控件开发了,再加上有句名言“知识就是力量”,那没得知识就没得力量了,所以没得办法,就利用Baidu + Google,googling了半下午。结果再次验证了Google的搜索实力确实比Baidu强悍啊,在此为Google最近的决定感到失望,牢骚就不多发了,还是进正题。以下是自己的一些新的总结和找到的一些学习资源。希望可以share.

    首先了解到,Page类继承自模板控件类TemplateControl Http处理程序接口IHttpHandler

    1.TemplateControl类是个abstract类,继承自Control类,ID命名容器控件INamingContainer,

    和设备筛选器接口IFilterResolutionService

    2. IHttpHandler接口是为了使用Http处理程序同步处理Http Web请求而实现的协定。有一个只SetIsReusable属性和一个方法ProcessRequest(HttpContext context)方法,用来处理Http Web请求。

         既然Page间接的继承自Control类,那下面就先从介绍Control类说起。

    Control类的生命周期有七个大的事件阶段,分别为Init事件,Load事件,DataBinding事件,PreRender事件,Render方法,Unload事件,Disposed事件。下面简单介绍下每个阶段;

    1.Init阶段,引发Init事件,执行OnInit(EventArgs e)虚方法。详细请参见处理继承的事件。

    2.然后执行TrackViewState(object savedState)虚方法,会根据页面IsPostBack属性,来确定是否LoadViewState(objcet savedState)来加载视图状态,以及如果控件继承自接口IPostBackDataHandler,还会实现LoadPostData(string postDataKey,System.Collections.Specialized.NameValueCollection postCollection),来处理回发数据。详细请参见处理回发数据维护控件中的状态

    3.Load阶段,引发Load事件,执行OnLoad(EventArgs e)虚方法。此时,Load事件树中的服务器控件已创建并初始化、状态已还原并且窗体控件反映了客户端的数据。详细参见处理继承的事件。

    4.之后根据页面IsPostBack属性,如果实现了接口IPostBackDataHandler则调用RaisePostDataChangedEvent() 方法,来处理引发更改事件以响应当前和以前回发之间的状态更改。如果实现如果已实现 IPostBackEventHandler接口,则引发RaisePostBackEvent(string eventArgument)方法的实现来处理,来处理引起回发的客户端事件,并在服务器上引发相应的事件。详细参见处理回发数据捕获回发事件。

    5.PreRender阶段,引发PreRender 事件,执行OnPreRender(EventArgs e)方法,在呈现输出之前执行任何更新。可以保存在预呈现阶段对控件状态所做的更改,而在呈现阶段所对的更改则会丢失。此阶段是对控件做任何更新的最后机会。详细请参见处理继承的事件。

    6.SaveViewState阶段,在此阶段后,自动将控件的 View State 属性保持到字符串对象中。此字符串对象被发送到客户端并作为隐藏变量发送回来。为了提高效率,控件可以重写 SaveViewState() 方法以修改 View State属性。详细请参见维护控件中的状态。

    7.呈现Render阶段,此阶段没有不适事件,执行Render()方法,来生成呈现给客户端的输出。详细参见呈现 ASP.NET 服务器控件

    8.Dispose阶段,执行Disponse()方法,执行销毁控件前的所有最终清理操作。在此阶段必须释放对昂贵资源的引用,如数据库链接。详细参见ASP.NET 服务器控件中的方法

    9.卸载Unload阶段,引发Unload事件,执行OnUnload()方法,来执行销毁控件前的所有最终清理操作。控件作者通常在 Dispose 中执行清除,而不处理此事件。

     

    以下2点要有所注意:   

    1.要重写 Event Name 事件,请重写 OnEventName 方法(并调用 base.OnEventName)。

    2.之上的方法和事件基本在自己创建控件时都可以重写 System.Web.UI.Controlabstract方法,但可以看出以下几个除外:LoadPostData 和 RaisePostDataChangedEvent 是 IPostBackDataHandler 接口的方法,而 RaisePostBackEvent 属于 IPostBackEventHandler 接口。如果控件参与回发数据处理,则必须实现 IPostBackDataHandler。如果控件收到回发事件,则必须实现 IPostBackEventHandler

    3.以上没有列出 CreateChildControls 方法,这是由于每当 ASP.NET 页框架需要创建控件树时就会调用该方法,且该方法调用并不限于控件生命周期的特定阶段。例如,可以在加载页时、在绑定数据过程中或者在呈现过程中调用 CreateChildControls,以及在动态创建控件的时候也可以调用的。

    下面给个自己创建个WebPart控件示范,功能比较简单,在页面上面实现Ifame实现内嵌页面的效果。

     

    1. using System;  
    2. using System.Collections.Generic;  
    3. using System.Text;  
    4. using System.Web;  
    5. using System.Web.UI;  
    6. using System.Web.UI.HtmlControls;  
    7. using System.Web.UI.WebControls.WebParts;  
    8.   
    9. namespace IframeWebpart  
    10. {  
    11.     public class Iframe:WebPart,INamingContainer  
    12.     {  
    13.         private int _width = 100;  
    14.         private int _height = 100;  
    15.         private HtmlTableCell _htc = new HtmlTableCell();  
    16.         private string _url = @"http://www.baidu.com";  
    17.   
    18.         [WebBrowsable(true),Personalizable(true)]  
    19.         public int IWidth  
    20.         {  
    21.             get { return _width; }  
    22.             set { _width = value; }  
    23.         }  
    24.   
    25.         [WebBrowsable(true),Personalizable(true)]  
    26.         public int IHeight  
    27.         {  
    28.             get { return _height; }  
    29.             set { _height = value; }  
    30.         }  
    31.   
    32.         [WebBrowsable(true), Personalizable(true)]  
    33.         public string Url  
    34.         {  
    35.             get { return _url; }  
    36.             set { _url = value; }  
    37.         }  
    38.   
    39.         protected override void CreateChildControls()  
    40.         {  
    41.             //base.CreateChildControls();  
    42.             this.Controls.Add(new LiteralControl("<table>"+"\n"));  
    43.             this.Controls.Add(new LiteralControl("<td>"+"\n"));  
    44.             this.Controls.Add(this._htc);  
    45.             this.Controls.Add(new LiteralControl("</td>"+"\n"));  
    46.             this.Controls.Add(new LiteralControl("</table>"+"\n"));  
    47.             if (!this.Page.IsPostBack)  
    48.             {  
    49.                 this.AddControls();  
    50.             }  
    51.   
    52.         }  
    53.   
    54.         protected override void OnLoad(EventArgs e)  
    55.         {  
    56.             base.OnLoad(e);  
    57.             //if (!this.Page.IsPostBack)  
    58.             //{  
    59.             //    this.AddControls();  
    60.             //}  
    61.         }  
    62.   
    63.         protected override void Render(HtmlTextWriter writer)  
    64.         {  
    65.             base.Render(writer);  
    66.         }  
    67.   
    68.         private void AddControls()  
    69.         {  
    70.             this._htc.Controls.Add(new LiteralControl("<iframe id='iframe1' src=""+this.Url+"" mce_src=""+this.Url+"" width='"+this.IWidth+"' height='"+this.IHeight+"'  marginheight='0' frameborder='0' scrolling='no' vspace='0' hspace='0'  marginwidth='0'  >"+"\n"));  
    71.             this._htc.Controls.Add(new LiteralControl("</iframe>"+"\n"));          
    72.         }  
    73.   
    74.     }  
    75. }  

     

     

    Control类的比较简单,下面介绍Page类,Page类的生命周期相对control要稍微复杂一些。(下面介绍参考了MSDN上面的介绍)

    普通的常规页面生命周期有:页请求,开始阶段,初始化,加载,验证,回发事件处理,呈现,卸载,除了页生命周期阶段以外,在请求前后还存在应用程序阶段,但是这些阶段并不特定于页。以下详细介绍;

    1页请求:发生在页面生命周期之前,用户请求页时,ASP.NET将确定是否需要分析和编译页,从而确定是否开始页面的生命周期,或者是否可以在不运行页的情况下发送页面缓存以进行响应。

    2开始:设置页属性,如:HttpContext以及其他属性;在此阶段,页面需要确定是回发请求还是新请求,并设置IsPostBack属性;设置页面的UICulture属性。

    3页面初始化:加载所有主题;控件生成,并设置UniqueID

    注:ViewStateControlState中的值还未加载至控件;如果页面是回发,则回发数据也还未加载;故此时控件可以访问,但值可能出错。

    4加载:如果当前请求是回发请求,则为控件加载ViewStateControlState中的值。

    5验证:调用所有验证程序控件的Validate方法,此方法将设置验证程序控件和页的IsValid属性。

    6回发事件处理:如果请求是回发请求,则调用所有事件处理程序。

    7呈现:首先对该页和所有控件进行保存视图状态,然后对每个控件调用Render方法,它会提供一个文本编写器,用于将控件的输入写入页的Response属性的OutputStream中。

    8卸载:完成呈现,并已将页发送至客户端、准备丢弃该页后,调用卸载。将卸载属性如:ResponseRequest等等,故之后如果在调用这些对象,都将出错异常的。

     

    在介绍Asp.net之前先来看两张关于页面的请求过程图片:

     

    第一张是个普通的页面请求过程

    第二张是个是个添加的Button按钮控件PostBack后的页面请求过程。

    比较这两张图片可以很清晰的得出以下两点内容。

    一. Asp.Net的页面生命周期,基本都有如下几个阶段;

    PreInit

    Init

    InitComplete

    PreLoad

    Load

    LoadComplete

    PreRender

    Render

    RenderComplete

    SaveState

    SaveStateComplete

    Render

    UnLoad

    二.在页面的响应生命周期阶段,控件的生命周期阶段也在相应同步进行着。

     

    下面也来个粗略的介绍;

    1.      PreInit阶段

    此阶段引发PreInit事件,执行OnPreInit()方法,完成的操作,有比如查IsPostBack属性来确定是

    不是第一次处理该页;创建或重新创建动态控件,动态设置主控页,动态设置Theme属性,读取或设置配置文件属性。注:如果请求是回发请求,则控件的值尚未从视图状态恢复,即:不应该在此事件中设置控件属性。

    2.      Init阶段

    在所有控件都已初始化,且应用了外观后由里到外引发Init事件,执行由自Control类继承得OnInit()方法,使用该事件来读取或初始化控件属性。

    3.      InitComplete阶段

    Page对象引发。使用该事件来处理要求先完成所有初始化工作的任务。执行OnInitComplete()方法。

    4.  PreLoad

     Page 引发该事件后,执行OnPreLoad(),它会为自身和所有控件加载视图状态,然后会处理 Request 实例包括的任何回发数据,如果需要在 Load 事件之前对页或控件执行处理,请使用该事件。

    5.  Load

    PagePage上调用OnLoad事件方法,然后以递归方式对每个子控件执行相同操作,如此循环往复,直到加载完本页和所有控件为止。使用OnLoad()事件方法来设置控件中的属性并建立数据库连接。

    6.  控件事件

    使用这些事件来处理特定控件事件,如 Button 控件的 Click 事件等。注:在回发请求中,如果页包含验证程序控件,请在执行任何处理之前检查Page和各个验证控件的IsValid属性。

    7.      LoadComplete

    引发LoadComplete事件,执行OnLoadComplete()方法,对需要加载页上的所有其他控件的任务使用该事件。

    8.      PreRender

    引发PreRender事件,执行由Control类继承来的OnPreRender()方法,使用该事件对页或其控件的内容进行最后更改。注:在该事件发生前的操作:Page对所有控件递归进行EnsureChildControl操作设置了DataSourceID属性的数据绑定控件会调用DataBind方法。

    9.  PreRenderComplete

       引发PreRenderComplete事件,执行的On PreRenderComplete方法。

    10.  SaveStateComplete
    引发SaveStateComplete事件,执行由OnSaveStateComplete(EventArgs e)方法,在该事件发生前,

    已针对页和所有控件保存了ViewState。将忽略此时对页或控件进行的任何更改。。

    11Render
    这不是事件;在处理的这个阶段,Page 对象会在每个控件上调用此方法。所有 ASP.NET Web 服务

    器控件都有一个用于写出发送给浏览器的控件标记的 Render 方法。如果创建自定义控件,通常要重写此

    方法以输出控件的标记。不过,如果自定义控件只合并标准的 ASP.NET Web 服务器控件,不合并自定

    义标记,则不需要重写 Render 方法。有关更多信息,请参见开发自定义 ASP.NET 服务器控件。用户

    控件(.ascx 文件)自动合并呈现,因此不需要在代码中显式呈现该控件

    12.Unload

    引发Unload事件,执行由Control类继承来的OnUnLoad()方法,对子控件由里向外执行此方法。

     

    注意点。当从 Page 类继承类时,除了可以处理由页引发的事件以外,还可以重写页的基类中的方法。例如,可以重写页的 InitializeCulture 方法,以便动态设置区域性信息。注意,在使用 Page_事件语法创建事件处理程序时,将隐式调用基实现,因此无需在方法中调用它。例如,无论是否创建 Page_Load 方法,始终都会调用页基类的 OnLoad 方法。但是,如果使用 override 关键字(在 Visual Basic 中为 Overrides)重写页的 OnLoad 方法,则必须显式调用基方法。例如,如果在页中重写 OnLoad 方法,则必须调用 base.Load(在 Visual Basic 中为 MyBase.Load)以运行基实现

     

    以上就是本人的理解和总结,比较简单,可以说只有的理解了简单Control类和Page类的通用生命周期,以后才可以分析复杂的问题,比如动态创建控件时的数据丢失问题等。再比如目前有不少人喜欢在开发Web时候,比较喜欢直接让新建的Page页面继承自Page类,在这个继承来里面来写一些实现用户身份验证功能,但是如果对页面的生命周期比较了解后,可以这样来做,首先写个继承自Page类的类,在这个类里面根据需要来重写abstract方法和写一些通用的用户身份验证方法,之后让自己的页面后台代码类来实现这个类,从而达到通用的效果。这样做对代码复用性的提高,大家觉得是否有帮助呢?

     

    以上拙见,如有错误之处,请帮忙指教。

     

     

    参考资料

    1.        MSDN文档ASP.NET 页生命周期概述

    2.       《庖丁解牛:纵向切入ASP.NET 3.5控件和组件开发技术》

    3.       Programming ASP.NET》学习笔记(控件)

    4.       SnowQuery的专栏

    5.       深入理解Asp.net动态控件

  • 相关阅读:
    ubuntu 更新软件
    如何在linux(lubuntu)下搭建C/C++开发环境
    Linux下如何查看版本信息
    知识点笔记
    Require.js中使用jQuery 插件
    async中常用总结
    node.js在遇到“循环+异步”时的注意事项
    前端性能优化
    生产/消费者问题
    线程与内存
  • 原文地址:https://www.cnblogs.com/chy8219/p/2036028.html
Copyright © 2020-2023  润新知