一起谈.NET技术,关于ASP.NET页面生命周期的整体把握
2011-09-02 00:20
681 查看
对于每一个.NET程序员,对于ASP.NET页面生命周期都有一定的了解和把握。关于一些细节方面请参考http://blog.sina.com.cn/s/blog_5f7aa2970100d5h4.html,内容比较详尽,本文将不再概述。本文主要是从继承以及视图状态,事件,委托,容器控件以及子控件这些方面来把握和控制整体的页面生命周期。
先看下下面4个相关页面的代码(为降低复杂度,很多代码被删减与精简,仅提供最基本的操作代码)。仅仅几个文件,先看下整体文件的布局,有一个整体的把握。
![](http://image20.it168.com/201011_0x0/352/4edff23a64f988ef.jpg)
(一)父类的相关事件以及处理
(二)用户控件(子控件)的相关内容
上面最主要的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; }
-->
这一步最关键,利用userEventControl.Changed+=new UserControl.UserEventControl.ChangedHandler(userEventControl_Changed),当事件触发时,我们能够通过userEventControl_Changed()方法获取点击的value值,用视图状态保存该值,进而进行相应的操作(控制)。页面显示如下:
![](http://image20.it168.com/201011_500x375/352/e3cec86be2187728.jpg)
(四)跟踪文件为当前目录下的trace.txt文件
在每个页面上的事件中增加自定义跟踪,可以发现如下情况:Init和Load都在每个控件上递归方式发生,但它们发生的顺序是相反的。每个子控件的Init与Unload事件在其容器引发相应的事件之前发生。容器的Load事件是在其子控件的Load事件之前发生。
trace.txt内容显示如下(生成页面的过程以及点击事件触发跟踪):
<!--
#div_code img { border: 0px none; }
-->
从前面的6句可以看出,子控件UserEventControl 的Init事件发生在UserParentPage 以及Default 的Init事件之前,而子控件UserEventControl 的Load事件发生在UserParentPage 以及Default 的Load事件之后。其中,父类UserParentPage 的事件发生在子类Default 的事件之前。
注:
这个地方明显有点不对劲,再反过去查看下子控件事件中的代码。发现
多了这一行this.Load += new System.EventHandler(this.Page_Load); Load事件中再一次触发了子控件的Page_Load方法,因此注销掉该句。
到此我们再看一下跟踪文件中的内容(将原有记录全清空),如下所示:
这里就分成了2次操作,第1次为加载显示的过程(1-7句),第2次为点击获取相应的值的过程(8-15句)。过程是差不多的,仅仅多了一个回传事件。这与上面总结的是一致的。
总结
通过父类、子类以及子控件之间的关系,加强对页面生命周期的理解,精简不必要的操作。通过事件和委托、视图状态能够很好的完成某些复杂的功能,具体应用本文将不再讲叙,仅仅是给读者一个引子。合理利用javascript:__doPostBack()和Request.Form["__EVENTARGUMENT"]能获得意想不到的效果。
Init和Load都在每个控件上递归方式发生,但它们发生的顺序是相反的。每个子控件的Init与Unload事件在其容器引发相应的事件之前发生。容器的Load事件是在其子控件的Load事件之前发生。这个仅仅是本人以前实现的功能的一个精简版本,希望对各位有所帮助。
先看下下面4个相关页面的代码(为降低复杂度,很多代码被删减与精简,仅提供最基本的操作代码)。仅仅几个文件,先看下整体文件的布局,有一个整体的把握。
![](http://image20.it168.com/201011_0x0/352/4edff23a64f988ef.jpg)
(一)父类的相关事件以及处理
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值,用视图状态保存该值,进而进行相应的操作(控制)。页面显示如下:
![](http://image20.it168.com/201011_500x375/352/e3cec86be2187728.jpg)
(四)跟踪文件为当前目录下的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事件之前发生。这个仅仅是本人以前实现的功能的一个精简版本,希望对各位有所帮助。
相关文章推荐
- 一起谈.NET技术,关于ASP.NET页面打印技术的总结
- 一起谈.NET技术,构建高性能ASP.NET站点之一 剖析页面的处理过程(前端)
- 一起谈.NET技术,asp.net页面中输出变量、Eval数据绑定等总结
- 一起谈.NET技术,asp.net 页面转向 Response.Redirect, Server.Transfer, Server.Execute的区别
- 一起谈.NET技术,ASP.NET MVC验证框架中关于属性标记的通用扩展方法
- ASP.NET页面生命周期的整体把握
- 一起谈.NET技术,关于ASP.NET与CLR相互关系的一些总结
- 一起谈.NET技术,ASP.NET配置错误页面浅析
- 一起谈.NET技术,关于大型ASP.NET应用系统的架构—如何做到高性能高可伸缩性
- ASP.NET页面生命周期的整体把握
- 一起谈.NET技术,ASP.NET页面间数据传递的方法
- 一起谈.NET技术,关于技术争论(尤其是ASP.NETWebForms 和 ASP.NETMVC 之争)
- 一起谈.NET技术,详解ASP.NET页面的aspx扩展
- 关于ASP.NET页面打印技术的总结
- 关于ASP.NET页面打印技术的总结
- 关于ASP.NET页面打印技术的总结
- 关于ASP.NET页面打印技术的总结
- 一起谈.NET技术,ASP.NET缓存简介
- 一起谈.NET技术,ASP.NET MVC的全球化方案
- 一起谈.NET技术,在Mono 2.8上部署ASP.NET MVC 2