關于ASP.NET頁面生命周期的整體把握

來源: JasenKin的博客  發布時間: 2010-11-28 22:18  閱讀: 1796 次  推薦: 0   原文鏈接   [收藏]  
摘要:本文主要是從繼承以及視圖狀態,事件,委托,容器控件以及子控件這些方面來把握和控制整體的頁面生命周期。

  對于每一個.NET程序員,對于ASP.NET頁面生命周期都有一定的了解和把握。關于一些細節方面請參考http://blog.sina.com.cn/s/blog_5f7aa2970100d5h4.html,內容比較詳盡,本文將不再概述。本文主要是從繼承以及視圖狀態,事件,委托,容器控件以及子控件這些方面來把握和控制整體的頁面生命周期。

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

1

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

 
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"];
}
}


protected override void OnInit(EventArgs e)
{
Core.Trace.TraceInfo(

"UserEventControl OnInit");
InitializeComponent();

base.OnInit(e);
}



private void InitializeComponent()
{

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

/// <summary>
/// 單擊時將觸發
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></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值,用視圖狀態保存該值,進而進行相應的操作(控制)。頁面顯示如下:

1

  (四)跟蹤文件為當前目錄下的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內容顯示如下(生成頁面的過程以及點擊事件觸發跟蹤): <!-- #div_code img { border: 0px none; } -->     

 
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: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 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 的事件之前。

  注:

 
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:29 828: UserEventControl OnLoad
2010-11-23 02:26:29 828: UserEventControl OnLoad !Page.IsPostBack==true

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

 
private void InitializeComponent()
{

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

  多了這一行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事件之前發生。這個僅僅是本人以前實現的功能的一個精簡版本,希望對各位有所幫助。

0
0
 
 
 

文章列表

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()