在每一次http的Request和Response周期asp.net web form都会执行一系列被称为控件生命周期的预定义过程
在第一次通过HTTP Get方法获取到页面后,每一次向服务端进行HTTP POST回传都会分为以下几个步骤:
1. 初始化控件树
2. 将回传的ViewState进行解析
3. 根据前几次的回传解析来为控件树中的每一个控件设置状态
4. 处理回传数据
5. 处理Page_Load事件
6. 通过PostBack通知控件的数据变化,并在必要的情况下更新控件状态
7. 执行基于控件状态改变的服务端事件(比如button的点击)
8. 将控件状态持久化为ViewState
9. 按照次序Render控件树中的每一个控件
10. Dispose整个页面和控件树
由上面的列表可以看出整个的用户Request和服务器Response的周期,首先是将状态解析并根据控件的状态来处理状态的改变,最后处理完后将这些Render回客户端,并将新的状态以ViewState的形式保存在客户端的hidden form中。
页面生命周期对应事件
在页面生命周期中,上面所说的每一个步骤都有一个对应的事件。这也就意味着你可以通过Override事件的执行方法来在页面周期中插入你自己的实现
服务端事件 |
页面生命周期 |
描述 |
Init |
Initialization |
初始化控件树 |
LoadViewState |
Unpack ViewState |
从ViewState里提取出状态信息 |
LoadControlState |
Unpack control state |
从控件状态中提取出状态信息 |
LoadPostData |
Handle form postback |
从PostBack信息中更新控件状态信息 |
Load |
Page_Load event |
执行Page_Load内的事件 |
TrackViewState |
Track ViewState |
|
RaisePostDataChangedEvent |
Initialization for server-side events |
通知控件回传的状态将改变其值 |
RaisePostBackEvent |
Execute server-side events |
对于指定的控件,如果状态信息改变,则引发该事件 |
PreRender |
Render process |
让每个空间接收最新的状态信息 |
SaveViewState |
Save ViewState |
保存ViewState |
SaveControlState |
Save control state |
|
Render |
Render process |
Render标准HTML,Render的HTML带有控件的状态信息 |
Dispose |
Dispose of control tree |
释放资源 |
服务器生命周期和HTTP GET以及HTTP POST
在System.Web.UI.Control基类定义了OnInit, OnLoad, OnPreRender, OnUnload,这四个事件可以被重写。而对于Dispose事件虽然Control也有定义,但并没有相应的OnDispose方法来引发事件,如果需要Dispose事件,需要实现IDispose接口。
在通常情况下,第一次访问aspx页面时通过HTTP GET方法,而第二次以后都会通过HTTP POST方法,而HTTP POST方式进行访问服务器时,所需要经历的过程要比GET方式多,因为它包含了数据回传处理,下面是示意图:
下面通过一个小Demo来查看控件的生命周期:
Demo Post回传生命周期
首先先写一个控件,对每个控件的上述事件进行覆盖,最后通过在页面Trace来查看
首先是控件的代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
namespace Life
{
[ToolboxData("<{0}:lifecycle runat=server></{0}:lifecycle>")]
public class Lifecycle : Control, IPostBackEventHandler, IPostBackDataHandler
{
protected override void OnInit(System.EventArgs e)
{
Trace("Lifecycle: Init Event.");
base.OnInit(e);
}
protected override void TrackViewState()
{
Trace("Lifecycle: Track ViewState.");
base.TrackViewState();
}
protected override void LoadViewState(object savedState)
{
Trace("Lifecycle: Load ViewState Event.");
base.LoadViewState(savedState);
}
protected override void LoadControlState(object savedState)
{
Trace("Lifecycle: Load ControlState Event.");
base.LoadControlState(savedState);
}
public override void DataBind()
{
Trace("Lifecycle: DataBind Event.");
base.DataBind();
}
public bool LoadPostData(string postDataKey,NameValueCollection postCollection)
{
Trace("Lifecycle: Load PostBack Data Event.");
Page.RegisterRequiresRaiseEvent(this);
return true;
}
protected override void OnLoad(System.EventArgs e)
{
Trace("Lifecycle: Load Event.");
base.OnLoad(e);
}
public void RaisePostDataChangedEvent()
{
Trace("Lifecycle: Post Data Changed Event.");
}
public void RaisePostBackEvent(string argument)
{
Trace("Lifecycle: PostBack Event.");
}
protected override void OnPreRender(System.EventArgs e)
{
Trace("Lifecycle: PreRender Event.");
Page.RegisterRequiresPostBack(this);
base.OnPreRender(e);
}
protected override object SaveViewState()
{
Trace("Lifecycle: Save ViewState.");
return base.SaveViewState();
}
protected override object SaveControlState()
{
Trace("Lifecycle: Save ControlState.");
return base.SaveControlState();
}
protected override void Render(HtmlTextWriter writer)
{
base.Render(writer);
Trace("Lifecycle: Render Event.");
writer.Write("<h3>LifeCycle Control</h3>");
}
protected override void OnUnload(System.EventArgs e)
{
Trace("Lifecycle: Unload Event.");
base.OnUnload(e);
}
public override void Dispose()
{
Trace("Lifecycle: Dispose Event.");
base.Dispose();
}
private void Trace(string info)
{
if (Context != null)
{
Context.Trace.Warn(info);
System.Diagnostics.Debug.WriteLine(info);
}
}
}
}
首先通过设置私有的Trace方法将Trace信息添加进页面当中,通过实现了IPostBackEventHandler和IPostBackDataHandler接口来实现Post方式回传所需要的几个方法。
控件在前台的代码如下:
首先在前台将Trace属性设置成True,其次注册控件
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default10.aspx.cs" Inherits="Default10" Trace="true" %>
<%@ Register Namespace="Life" TagPrefix="lc" %>
然后将控件放在页面内:
<lc:Lifecycle runat="server"></lc:Lifecycle>
输出结果如下:
可以看出,我们对事件的实现都已经插入页面的生命周期内.