• 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事件之前发生。这个仅仅是本人以前实现的功能的一个精简版本,希望对各位有所帮助。

     

     源代码下载地址: PageEventProcess.rar

  • 相关阅读:
    react的CSS中 :global的含义
    TypeScript中的问号 ? 与感叹号 ! 的含义
    移动端1px问题的解决方案
    原生js实现call,apply以及bind
    哪些场景不能使用箭头函数
    线性渐变、径向渐变以及圆锥渐变
    vue 开发中实现provide和inject实现依赖注入
    inline-block元素去除间隙
    clientWidth、offsetWidth、scrollWidth的区别
    session、token和cookie
  • 原文地址:https://www.cnblogs.com/jasenkin/p/asp_net_page_process.html
Copyright © 2020-2023  润新知