asp.net页面生存周期之页面的建立

来源:互联网 发布:知乎的楠爷李楠 编辑:程序博客网 时间:2024/05/16 17:56

每次客户端请求都会创建页面实例,它的执行使自身及其包含的控件经历页面生命周期的各个阶段。页面的执行起始于http运行库调用ProcessRequest时,该方法将启动页面并控制它的生命周期。生命周期由一系列阶段和步骤组成。一些阶段可以通过用户编码的时间进行控制,而一些需要对方法进行重写。其他阶段(更确切的说是子阶段)没有被公开,因而开发者无法控制。

页面的生命周期可以分为三个阶段:建立阶段、回发阶段和终结阶段。每个阶段会有子阶段,分别由若干步骤和事件引发点组成。这里描述的生命周期包括所有可能的路径。注意,具体情况会返回过程(跨页投递、脚本回调和回发)的不同而略有不同。

页面的建立

当http运行库实例化一个页面类对当前请求进行处理时,页面的构造函数会生成一个控件树。该控件树会关联至实际的类,这些类的请求过程开始时,所有子控件和页面的内部对象(如http上下文对象,请求对象和响应对象等)都会被设置。

页面生命周期的第一个阶段是确定运行库处理当前页面请求的原因。这个原因有很多种:常规请求、回发、跨页投递或回调。基于实际的原因,页面对象会配置其内部状态,如果包含被投递的值,还会根据请求的方法准备该值的集合。在第一个阶段过后,页面便为引发事件来执行用户代码做好了准备。

PreInit事件

这是asp.net引入的事件,它是页面生命周期的入口点。该事件被引发时,页面尚未与母版页和主题相关联。但页面滚动条位置已被恢复,被投递的数据变为可用,且所有的页面控件已被实例化,其属性页基于在aspx源中的默认值进行了设置(注意,如果没有在aspx源中显示指定,这是的控件是没有ID的),在这个阶段中,可以对母版页进行调换,或对主题进行编程。该事件仅对页面有效。IsCallBack、IsCrossPagePostBack和IsPostBack会在这时被设置。

Init事件

在这个阶段,母版页和主题(如果存在)会被设定,不能再被更改。页面处理程序(即Page类的ProcessRequest方法)开始执行,对所有子控件进行迭代,使其有机会在上下文环境下初始化他们的状态。所有子控件都有自己的OnInit方法,后者以递归方式被调用。对于控件集合中的每个控件,都设置有命名容器和特定Id(如果没有在源中分配)。

Init事件首先会处理子控件,然后是页面。在这个阶段,页面和控件通常开始加载其部分状态。此时,视图状态尚未被恢复。

InitComplete事件

该事件是asp.net2.0引入的,页面专有,用于指示初始化子阶段的结束。对于页面来说,在Init和InitComplete事件之间只有一个操作会执行--启用视图状态的变更跟踪功能。视图状态的跟踪是这样的一种操作,它最终使控件能够真正的将所有以编程方式添加到ViewState集合中的值,存储在持久性介质中。简而言之,对于没有实施视图跟踪的控件,添加其viewstate中的值将在回发间丢失。

在控件引发各自的Init事件后,视图状态跟踪会立即启动,页面也不例外(归根结底,页面也是一种控件)。

(要点:对于上述说明,有一点需要注意:在Initcomplete前,任何写入viewstate集合中的值,在下一次回发时都不在可用。对于asp,net1.x,必须等待Load事件被引发,才能安全地更改页面和控件的视图状态)。

视图状态的恢复

如果页面因回发而被处理(即IsPostBack属性为true),隐藏字段_VIEWSTATE的值会被恢复。隐藏字段_VIEWSTATE用于在请求结束时,保存所有控件的视图状态。页面的整体视图状态是一种调用上下文,包含页面每个组成控件上一次发往浏览器的状态信息。

在这个阶段,每个控件会获得更新其当前状态的机会,恢复上一次请求时的状态。视图状态恢复过程不会引发任何事件。如果需要对此进行定制,则需借助于LoadViewState方法的重写(该方法是Control类中受保护的虚拟成员)。

处理被投递的数据

Http请求中打包的所有客户端数据(即所有定义在form标签中输入字段的内容)会在这时被处理。被投递的数据通常采用下面这种形式:

TextBox1=text&DropDownList1=selectedItem$Buttoon1=Submit

该字符串用的键值对被“&”分隔。这些值会被加载到一个内部使用的集合中。页面处理程序会视图寻找被投递集合中的名称与页面中控件ID的匹配项。如果找到匹配项,处理程序会检查该服务器控件是否已实现IPostBackDataHandler接口。如果已经实现 ,该接口的方法会被调用,为使用被投递数据更新该控件状态提供机会。具体来讲,页面处理程序会调用该接口的LoadPostData方法。如果他返回true(即,状态已更新),该控件将被添加到一个独立的集合中,等待进一步指示。

如果没有找到与被投递的名称对应的服务器控件,它将被搁置于一个临时的独立集合中,稍后再试。

PreLoad事件

PreLoad 事件是 asp.net引入的,仅用于指示页面已完成系统级的初始化,即将进入另一个阶段。接下来的阶段会为页面中用户代码的执行提供机会,为执行和呈现对该页面进一步配置。只有页面会引发该事件

Load 事件

Load事件首先由页面组成,之后以递归方式分别由所有的子控件引发。这时,页面中的控件树会被创建,各控件的状态完全反映之前的状态,并获得了从客户端投递过来的所有数据。对于执行处理逻辑和页面行为的初始化代码,页面已做好准备。这时访问控件属性和视图状态是绝对安全的。

处理动态创建的控件

当页面中所有控件完成了显示前的初始化后,页面处理程序会对那些没有与现有控件相对应的被投递的数据做再次尝试。该行为会对之前搁置的键值对再次处理。显然,这一特殊的方式提供了一种不可思议的特殊方案--使用动态创建的控件。

可以想象,就是讲控件动态的添加到页面的树中(例如,为响应某个用户发出的动作)。如前所述,每次回发,页面都将要根据原状态重新生成,因而任何有关动态创建控件的信息会丢失。另一方面,当页面的窗体提交后,动态控件会被填充合法且有效的信息,并以常规方式投递。根据设计,初始的动态控件ID不可能与某个服务器控件的ID相匹配。然而asp.net会识别可能在Load 事件中被创建的控件。这样,在用户代码运行一段后,便可以再次尝试寻找可能的匹配项。

如果动态控件在Load事件中被创建,就可能找到匹配项,从而该控件可以使用被投递的数据对状态进行刷新。


0 0
原创粉丝点击