在这个页面级的事件中,所有在设计时创建的控件都将被用默认值做初始化。例如,如果你有一个Text属性值为“Hello”的TextBox控件,则此时这个属性被设置。我们也可以在这里动态的创建控件。
这个事件仅仅发生在页级别的类中,用户控件和母版页没有这个事件。
下面的代码示例了如何重写这个方法以增加你的自定义代码
protected override void OnPreInit(EventArgs e)
{
//custom code
base.OnPreInit(e);
}
注意,我们只能在PreInit()事件中动态的设置themes,且应该在PreInit()事件或该事件之前加载母版页。
2. OnInit()
在这个事件里,我们能读出控件的属性(在设计模式中设置的)。但是我们不能读出用户设置的值,因为得到用户设置的值是在LoadPostData()事件被激发之后。不过在这个事件中我们可以得到POST数据,如下
string selectedValue = Request.Form[controlID].ToString();
3. LoadViewState
这个事件仅仅在回发之后被激发(IsPostBack == true)。在这个事件中runtime从隐藏域中分解出view state并加载到所有启用了view state的控件。
4. LoadPostBackData
这个事件也仅仅是在回发之后被激发。
在这个事件里实现了IPostBackDataHandler接口的控件从HTTP的POST数据中得到值。注意,textbox控件不能从view state中获得值,而是在此事件中从POST数据中获得值。所以即使有些控件没有启用view state,只要它实现了IPostBackDataHandler接口就可以从HTTP的POST数据中得到值。
另一个重要的知识点是如果我们有一个DropDownList控件并动态的给它增加一些选择项,那么runtime将不能得到这些值除非启用了view state(即使控件继承自IPostBackDataHandler接口)。这个原因就是在HTTP的POST数据中的每一个控件只能有一个值,并且POST数据中的所有值都不会被保存,除了使用view state。
5. Page_Load
这是最常用的方法了,而且是一些开发新手放置他们代码的第一个地方,有些新手们往往认为这就是Page类第一个触发的方法。这个方法是混淆我们Page生存周期的罪魁祸首之一。
注意:如果页里有任何用户控件的话,那么用户控件的Load方法将在页类的Load方法之后被触发。除了Init()和Unload()之外的所有事件都是从最外面到最里面被激发的,所以页的Page_Load()之后,页内的其它控件的Load方法才被触发。
6. Control Event Handlers
事件处理(比如像Button1_Click()之类的)是定义在ASPX页面中的,有一些开发人员认为当单击一个按钮后会立即出发Button_Click() ,他们忘了在这个事件触发之前首先要触发Page_Load。
7. PreRender
如果我们想改变某一个控件的值,这是最后的机会了
8. SaveViewState
控件的ViewState被存储在form的隐藏域中
9. Render
呈现页面和控件
10. Unload
这是最后的清理操作
动态控件
现在我们已经知道了页的生存周期的重要事件,接下来让我们关注一下如何创建以及保持动态生成控件的状态。有的时候我们需要动态的生成控件,比如我原来管理的一个酒店预订的项目,用户在一个TextBox里输入房间号,根据这个值动态的生成一个用户控件来显示该房间的详细信息。
开发人员虽然能动态的生成用户控件,但是却不能保存用户控件的状态。当我看了代码后,他们把生成控件的代码写到了Button的Click事件里。根据我们上面所讨论的,Button_Click()在LoadViewState()和LoadPostData()之后触发,而控件的值是要在view state或POST数据中取得的。
所以除非在Page_Init()或Pre_Init()方法里重新创建控件(它们发生在LoadViewState和LoadPostData之前),这样就可以在下一个事件里获得控件的值。
现在,如果把代码写到Page_Init()事件里的话,将不能得到用户在TextBox(它是一个静态控件)里输入的值。原因就在于这是Page_Init()事件,控件的值被初始化为它们设计时的默认值,而不会得到用户输入的值。
所以如果要在这里访问到用户输入的值话只有一个办法,就是从POST数据中取值。代码如下
protected override void OnInit(EventArgs e)
{
// 通过Post数据得到用户在TextBox里输入的值
string selectedValue ;
if(Request.Form["txtNoOfRooms"] != null)
selectedValue = Request.Form["txtNoOfRooms"].ToString();
// 动态生成控件的代码
base.OnInit(e);
}
如果你在Page_Load事件里创建一个动态控件,并把它添加到PlaceHolder或Panel里(要打开view state),那么动态控件将会维持它的状态,即使它不是在Page_Init()中创建的,为什么?
原因就是控件一旦被添加到页的控件树里,TrackViewState()方法就负责跟踪其状态。只要控件被添加到控件树里,这个方法就会被自动的触发。因为这个原因,对控件的任何修改(如添加item之类的)都应该在动态控件被添加到页的控件树之后来做,否则其状态将丢失。请看如下代码
protected void Page_Load(object sender, EventArgs e)
{
// 创建一个DropDownList
DropDownList d = new DropDownList();
// TrackViewState()方法将被触发去跟踪这个DropDownList的状态,所以其状态将被保持
PlaceHolder1.Controls.Add(d);
if (!IsPostBack)
{
d.Items.Add("test1");
d.Items.Add("test2");
}
}
下面的代码则不会保持动态控件的状态
protected void Page_Load(object sender, EventArgs e)
{
// 动态创建一个控件
DropDownList d = new DropDownList();
if (!IsPostBack)
{
d.Items.Add("test1");
d.Items.Add("test2");
}
// "test1"和"test2"值将丢失
PlaceHolder1.Controls.Add(d);
}