天天看點

一起談.NET技術,關于ASP.NET頁面生命周期的整體把握

  先看下下面4個相關頁面的代碼(為降低複雜度,很多代碼被删減與精簡,僅提供最基本的操作代碼)。僅僅幾個檔案,先看下整體檔案的布局,有一個整體的把握。

一起談.NET技術,關于ASP.NET頁面生命周期的整體把握

  (一)父類的相關事件以及處理

public class UserParentPage:System.Web.UI.Page

{

/// <summary>

/// 對回傳資料的處理,以及其他内容的設定、擷取

/// </summary>

/// <param name="e"></param>

protected override void OnInit(EventArgs e)

Core.Trace.TraceInfo("UserParentPage OnInit");

base.OnInit(e);

//編寫相應的代碼防止SQL注入

//System.Web.HttpContext.Current.Request.QueryString/Form

//根據上下文對象來檢測,以及做出相應的處理

//以及其他一些内容的設定、控制等等

}

protected override void OnLoad(EventArgs e)

Core.Trace.TraceInfo(

"UserParentPage OnLoad");

base.OnLoad(e);

//編寫相應的代碼對整體頁面的控制

  (二)使用者控件(子控件)的相關内容

public partial class UserEventControl : System.Web.UI.UserControl

public delegate void ChangedHandler();

public event ChangedHandler Changed;

private void Page_Load(object sender, System.EventArgs e)

Core.Trace.TraceInfo("UserEventControl OnLoad");

if (!Page.IsPostBack)

Core.Trace.TraceInfo("UserEventControl OnLoad !Page.IsPostBack==true");

SetContent();

private void SetContent()

int len =12,num = 2,perRowMaxCount=8;

System.Text.StringBuilder table = new System.Text.StringBuilder();

for (int i = 0; i <= num; i++)

table.Append(@"<table bordercolor='black' width='100%'><tr align='left'>");

for (int j = 0; j < perRowMaxCount; j++)

int p = i * perRowMaxCount + j;

if (p < len)

string paramValue ="param"+p.ToString();

string showValue ="show"+p.ToString();

table.Append(string.Format(@"<td width='12.5%'>

<a href='javascript:__doPostBack(""{2}"",""{0}"")' CommandName=""{0}"" class='line'>

<font>{1}</font></a></td>", paramValue,showValue, lbtnShow.ClientID.Replace(

"_lbtnShow", "$lbtnShow")));

else

table.Append(string.Format(@"<td width='12.5%'></td>"));

table.Append(@"</tr></table>");

lblShow.Text = table.ToString();

public string CurrentID

set

ViewState["CurrentID"] = value;

get

return (string)ViewState["CurrentID"];

"UserEventControl OnInit");

InitializeComponent();

private void InitializeComponent()

this.lbtnShow.Click += new System.EventHandler(this.lbtnShow_Click);

this.Load += new System.EventHandler(this.Page_Load);

/// 單擊時将觸發

/// <param name="sender"></param>

private void lbtnShow_Click(object sender, System.EventArgs e)

Core.Trace.TraceInfo("UserEventControl lbtnShow_Click");

CurrentID = Request.Form["__EVENTARGUMENT"];//擷取回傳值

SetContent();//設定内容----因為有些内容被修改過,如樣式什麼的,本例忽略

Changed();//觸發事件

  上面最主要的3點:

  (1)javascript:__doPostBack()和Request.Form["__EVENTARGUMENT"];__doPostBack()第一個參數必須用控件的name 而不是ID。控件名為将父控件ID用$符号連接配接起來的。第二個參數是傳給控件的Value值。第一個參數對應 Request.Form["__EVENTTARGET"]; 第二個參數對應Request.Form["__EVENTARGUMENT"]。此函數是DOTNET 的伺服器控件産生的,是以要使用此函數,必須整個頁面上至少要有一個控件可以回傳頁面。其實,dotnet 伺服器控件在頁面上産生兩個隐藏的控件一個名為__EVENTTARGET ,另一個名為__EVENTARGUMENT。

  (2)ViewState視圖狀态儲存的是頁面級别的内容。CurrentID = Request.Form["__EVENTARGUMENT"];

  (3)點選後将導緻事件的觸發(回傳)。 Changed();

  (三)頁面的事件與委托處理

<!--

#div_code img { border: 0px none; }

-->

public partial class Default : Core.UserParentPage

protected void Page_Init(object sender, EventArgs e)

Core.Trace.TraceInfo("Default OnInit");

protected void Page_Load(

object sender, EventArgs e)

Core.Trace.TraceInfo("Default Page_Load");

userEventControl.Changed+=new

UserControl.UserEventControl.ChangedHandler(userEventControl_Changed);

private void userEventControl_Changed()

Core.Trace.TraceInfo("Default userEventControl_Changed");

string id = userEventControl.CurrentID;

ViewState["ID"] =id;//儲存狀态進行相應的處理

lblShow.Text =id;

  這一步最關鍵,利用userEventControl.Changed+=new UserControl.UserEventControl.ChangedHandler(userEventControl_Changed),當事件觸發時,我們能夠通過userEventControl_Changed()方法擷取點選的value值,用視圖狀态儲存該值,進而進行相應的操作(控制)。頁面顯示如下:

一起談.NET技術,關于ASP.NET頁面生命周期的整體把握

  (四)跟蹤檔案為目前目錄下的trace.txt檔案

public static class Trace

private static string logPath = HttpContext.Current.Request.PhysicalApplicationPath;

public static void TraceInfo(string information)

string path = logPath + @"trace.txt";

string sqltemp = DateTime.Now.ToString("yyy-MM-dd hh:mm:ss fff") + ": "

+ information;

FileStream fs = null;

if (!File.Exists(path))

fs = File.Create(path);

fs.Close();

StreamWriter sw = new StreamWriter(path, true, Encoding.UTF8);

sw.WriteLine(sqltemp);

sw.Close();

  在每個頁面上的事件中增加自定義跟蹤,可以發現如下情況:Init和Load都在每個控件上遞歸方式發生,但它們發生的順序是相反的。每個子控件的Init與Unload事件在其容器引發相應的事件之前發生。容器的Load事件是在其子控件的Load事件之前發生。

  trace.txt内容顯示如下(生成頁面的過程以及點選事件觸發跟蹤):

2010-11-23 02:26:29 828: UserEventControl OnInit

2010-11-23 02:26:29 828: UserParentPage OnInit

2010-11-23 02:26:29 828: Default OnInit

2010-11-23 02:26:29 828: UserParentPage OnLoad

2010-11-23 02:26:29 828: Default Page_Load

2010-11-23 02:26:29 828: UserEventControl OnLoad

2010-11-23 02:26:29 828: UserEventControl OnLoad !Page.IsPostBack==true

2010-11-23 02:26:31 171: UserEventControl OnInit

2010-11-23 02:26:31 171: UserParentPage OnInit

2010-11-23 02:26:31 171: Default OnInit

2010-11-23 02:26:31 171: UserParentPage OnLoad

2010-11-23 02:26:31 171: Default Page_Load

2010-11-23 02:26:31 171: UserEventControl OnLoad

2010-11-23 02:26:31 171: UserEventControl lbtnShow_Click

2010-11-23 02:26:31 171: Default userEventControl_Changed

  從前面的6句可以看出,子控件UserEventControl 的Init事件發生在UserParentPage 以及Default 的Init事件之前,而子控件UserEventControl 的Load事件發生在UserParentPage 以及Default 的Load事件之後。其中,父類UserParentPage 的事件發生在子類Default 的事件之前。

  注:

  這個地方明顯有點不對勁,再反過去檢視下子控件事件中的代碼。發現

  多了這一行this.Load += new System.EventHandler(this.Page_Load); Load事件中再一次觸發了子控件的Page_Load方法,是以登出掉該句。

  到此我們再看一下跟蹤檔案中的内容(将原有記錄全清空),如下所示:

2010-11-23 02:46:11 281: UserEventControl OnInit

2010-11-23 02:46:11 281: UserParentPage OnInit

2010-11-23 02:46:11 281: Default OnInit

2010-11-23 02:46:11 281: UserParentPage OnLoad

2010-11-23 02:46:11 281: Default Page_Load

2010-11-23 02:46:11 281: UserEventControl OnLoad

2010-11-23 02:46:11 281: UserEventControl OnLoad !Page.IsPostBack==true

2010-11-23 02:46:13 265: UserEventControl OnInit

2010-11-23 02:46:13 265: UserParentPage OnInit

2010-11-23 02:46:13 265: Default OnInit

2010-11-23 02:46:13 265: UserParentPage OnLoad

2010-11-23 02:46:13 265: Default Page_Load

2010-11-23 02:46:13 265: UserEventControl OnLoad

2010-11-23 02:46:13 265: UserEventControl lbtnShow_Click

2010-11-23 02:46:13 281: Default userEventControl_Changed

  這裡就分成了2次操作,第1次為加載顯示的過程(1-7句),第2次為點選擷取相應的值的過程(8-15句)。過程是差不多的,僅僅多了一個回傳事件。這與上面總結的是一緻的。

  總結

  通過父類、子類以及子控件之間的關系,加強對頁面生命周期的了解,精簡不必要的操作。通過事件和委托、視圖狀态能夠很好的完成某些複雜的功能,具體應用本文将不再講叙,僅僅是給讀者一個引子。合理利用javascript:__doPostBack()和Request.Form["__EVENTARGUMENT"]能獲得意想不到的效果。

  Init和Load都在每個控件上遞歸方式發生,但它們發生的順序是相反的。每個子控件的Init與Unload事件在其容器引發相應的事件之前發生。容器的Load事件是在其子控件的Load事件之前發生。這個僅僅是本人以前實作的功能的一個精簡版本,希望對各位有所幫助。

繼續閱讀