zoukankan      html  css  js  c++  java
  • 一起谈.NET技术,关于ASP.NET页面生命周期的整体把握 狼人:

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

  • 相关阅读:
    poj 1088 滑雪
    位运算与bitset
    hdu 4607 Park Visit
    树的直径
    codeforces 495D Sonya and Matrix
    German Collegiate Programming Contest 2015(第三场)
    BAPC 2014 Preliminary(第一场)
    Benelux Algorithm Programming Contest 2014 Final(第二场)
    E. Reachability from the Capital(tarjan+dfs)
    poj2104 K-th Number(划分树)
  • 原文地址:https://www.cnblogs.com/waw/p/2163151.html
Copyright © 2011-2022 走看看