ASP.NET页面生命周期的整体把握

  对于每一个.NET程序员,对于ASP.NET页面生命周期都有一定的了解和把握。关于一些细节方面请参考http://blog.sina.com.cn/s/blog_5f7aa2970100d5h4.html,内容比较详尽,本文将不再概述。本文主要是从继承以及视图状态,事件,委托,容器控件以及子控件这些方面来把握和控制整体的页面生命周期。

      先看下下面4个相关页面的代码(为降低复杂度,很多代码被删减与精简,仅提供最基本的操作代码)。仅仅几个文件,先看下整体文件的布局,有一个整体的把握。              

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

(一)父类的相关事件以及处理

 1     public   class  UserParentPage:System.Web.UI.Page
 2      {
 3           ///   <summary>
 4           ///  对回传数据的处理,以及其他内容的设置、获取
 5           ///   </summary>
 6           ///   <param name="e"></param>
 7           protected   override   void  OnInit(EventArgs e)
 8          {
 9              Core.Trace.TraceInfo( " UserParentPage  OnInit " );
10               base .OnInit(e);
11               // 编写相应的代码防止SQL注入
12               // System.Web.HttpContext.Current.Request.QueryString/Form
13               // 根据上下文对象来检测,以及做出相应的处理
14               // 以及其他一些内容的设置、控制等等
15          }
16 
17           protected   override   void  OnLoad(EventArgs e)
18          {
19              Core.Trace.TraceInfo( " UserParentPage  OnLoad " );
20               base .OnLoad(e);
21               // 编写相应的代码对整体页面的控制
22          }
23      }

 

 (二)用户控件(子控件)的相关内容

 1    public   partial   class  UserEventControl : System.Web.UI.UserControl
 2      {
 3           public   delegate   void  ChangedHandler();
 4           public   event  ChangedHandler Changed;
 5           private   void  Page_Load( object  sender, System.EventArgs e)
 6          {
 7              Core.Trace.TraceInfo( " UserEventControl  OnLoad " );
 8               if  ( ! Page.IsPostBack)
 9              {
10                  Core.Trace.TraceInfo( " UserEventControl  OnLoad  !Page.IsPostBack==true " );
11                  SetContent();
12              }
13          }
14           private   void  SetContent()
15          {
16               int  len  = 12 ,num  =   2 ,perRowMaxCount = 8 ;         
17              System.Text.StringBuilder table  =   new  System.Text.StringBuilder();            
18               for  ( int  i  =   0 ; i  <=  num; i ++ )
19              {
20                  table.Append( @" <table  bordercolor='black' width='100%'><tr align='left'> " );
21                   for  ( int  j  =   0 ; j  <  perRowMaxCount; j ++ )
22                  {
23                       int  p  =  i  *  perRowMaxCount  +  j;
24                       if  (p  <  len)
25                      {
26                           string  paramValue  = " param " + p.ToString();
27                           string  showValue  = " show " + p.ToString();
28                          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 " )));
29                      }
30                       else
31                      {
32                          table.Append( string .Format( @" <td width='12.5%'></td> " ));
33                      }
34                  }
35                  table.Append( @" </tr></table> " );
36              }
37              lblShow.Text  =  table.ToString();
38          }
39 
40           public   string  CurrentID
41          {
42               set
43              {
44                  ViewState[ " CurrentID " =  value;
45              }
46               get
47              {
48                   return  ( string )ViewState[ " CurrentID " ];
49              }
50          }
51 
52           protected   override   void  OnInit(EventArgs e)
53          {
54              Core.Trace.TraceInfo( " UserEventControl  OnInit " );
55              InitializeComponent();
56               base .OnInit(e);
57          }
58 
59           private   void  InitializeComponent()
60          {
61               this .lbtnShow.Click  +=   new  System.EventHandler( this .lbtnShow_Click);
62               this .Load  +=   new  System.EventHandler( this .Page_Load);
63          }
64           ///   <summary>
65           ///  单击时将触发
66           ///   </summary>
67           ///   <param name="sender"></param>
68           ///   <param name="e"></param>
69           private   void  lbtnShow_Click( object  sender, System.EventArgs e)
70          {
71              Core.Trace.TraceInfo( " UserEventControl  lbtnShow_Click " );
72              CurrentID  =  Request.Form[ " __EVENTARGUMENT " ]; // 获取回传值
73              SetContent(); // 设置内容----因为有些内容被修改过,如样式什么的,本例忽略
74              Changed(); // 触发事件
75          }
76      }

 

上面最主要的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();

 

(三)页面的事件与委托处理

 1  public   partial   class  Default : Core.UserParentPage
 2      {
 3           protected   void  Page_Init( object  sender, EventArgs e) 
 4          {
 5              Core.Trace.TraceInfo( " Default  OnInit " );
 6          }
 7 
 8           protected   void  Page_Load( object  sender, EventArgs e)
 9          {
10              Core.Trace.TraceInfo( " Default   Page_Load " );
11              userEventControl.Changed += new  UserControl.UserEventControl.ChangedHandler(userEventControl_Changed);
12          }
13 
14           private   void  userEventControl_Changed() 
15          {
16              Core.Trace.TraceInfo( " Default   userEventControl_Changed " );
17             
18               string  id  =  userEventControl.CurrentID;
19              ViewState[ " ID " = id; // 保存状态进行相应的处理
20              lblShow.Text  = id;
21          }
22      }

 

      这一步最关键,利用userEventControl.Changed+=new UserControl.UserEventControl.ChangedHandler(userEventControl_Changed),当事件触发时,我们能够通过userEventControl_Changed()方法获取点击的value值,用视图状态保存该值,进而进行相应的操作(控制)。页面显示如下:


        

(四)跟踪文件为当前目录下的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: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

这个地方明显有点不对劲,再反过去查看下子控件事件中的代码。发现

1    private   void  InitializeComponent()
2          {
3               this .lbtnShow.Click  +=   new  System.EventHandler( this .lbtnShow_Click);
4               this .Load  +=   new  System.EventHandler( this .Page_Load);
5          }

 

多了这一行this.Load += new System.EventHandler(this.Page_Load);  Load事件中再一次触发了子控件的Page_Load方法,因此注销掉该句。

 

到此我们再看一下跟踪文件中的内容(将原有记录全清空),如下所示:

 1  2010 - 11 - 23   02 : 46 : 11   281 : UserEventControl  OnInit
 2  2010 - 11 - 23   02 : 46 : 11   281 : UserParentPage  OnInit
 3  2010 - 11 - 23   02 : 46 : 11   281 : Default  OnInit
 4  2010 - 11 - 23   02 : 46 : 11   281 : UserParentPage  OnLoad
 5  2010 - 11 - 23   02 : 46 : 11   281 : Default   Page_Load
 6  2010 - 11 - 23   02 : 46 : 11   281 : UserEventControl  OnLoad
 7  2010 - 11 - 23   02 : 46 : 11   281 : UserEventControl  OnLoad   ! Page.IsPostBack == true
 8  2010 - 11 - 23   02 : 46 : 13   265 : UserEventControl  OnInit
 9  2010 - 11 - 23   02 : 46 : 13   265 : UserParentPage  OnInit
10  2010 - 11 - 23   02 : 46 : 13   265 : Default  OnInit
11  2010 - 11 - 23   02 : 46 : 13   265 : UserParentPage  OnLoad
12  2010 - 11 - 23   02 : 46 : 13   265 : Default   Page_Load
13  2010 - 11 - 23   02 : 46 : 13   265 : UserEventControl  OnLoad
14  2010 - 11 - 23   02 : 46 : 13   265 : UserEventControl  lbtnShow_Click
15  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事件之前发生。这个仅仅是本人以前实现的功能的一个精简版本,希望对各位有所帮助。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值