asp.net WebForm 事件响应模型

版权声明:本文为博主原创文章,未经博主允许不得转载。如果感觉文章哪里写的不对或者存在疑问,欢迎留言,共同学习、进步! https://blog.csdn.net/ydm19891101/article/details/50552611

大家在asp.net WebForm的开发中最常做的恐怕就是拖一个服务器控件到窗体内,双击该控件就能为该控件添加后台代码,很简单。如按钮控件,当我们运行程序,点击按钮时会触发我们编写的按钮点击事件。用大家可能都会用,可你有没有仔细想过这是为什么呢?

我们常称WebForm开发为事件响应开发,这里面很重要的一个原因就是微软的事件响应模型。

在传统的WinForm开发阶段,我们习惯于拖拉控件、双击添加事件代码。不过那个时候的前台事件和后台方法是显示绑定的,我们可以手动绑定也可以自动绑定。而到了WebForm时代,我们同样可以拖拉控件,也可以双击添加后台事件代码(所以也导致很多初学者对WinForm和WebForm分不清楚)。但是这个绑定过程,我们看不到了,微软将这个绑定过程对我们程序员透明化了。而正是这个过程的透明化,导致很多人将WebForm的很多原理性东西给忽略了。如请求-处理-响应作为Web开发的三个主要过程,在WebForm开发中,我们完全可以忽略对他们的了解而开发出漂亮的网站。如果想要提升自己,我们必须对WebForm开发中的事件响应模型作深入了解。

在进一步了解之前,你还需要对以下几个内容有一些了解:

(1)页面的生命周期

(2)asp.net 原理

OK,如果你已经对上面的知识有了简单了解,那么我们就先动手建一个asp.net Web应用程序,通过具体的程序一步一步深入的来讲解。

新建一个ASP.NET Web应用程序,默认生成一个Default.aspx页面。Default.aspx页面中的第一行是一条页面指令:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="AspxEventsModel._Default" %>

其中CodeBehind属性指定代码后置类,Inherits属性指定继承的类所在的命名空间以及类名,AutoEventWireup属性是可以赋值为true和false,默认是赋值为true(关于该属性的详细使用请参考asp.net页面的AutoEventWireup="true"属性设置)。
我们先在Default.aspx页面中放入两个Literal服务器控件:

        <asp:Literal ID="LiInit" runat="server"></asp:Literal>
        <br />
        <asp:Literal ID="LiLoad" runat="server"></asp:Literal>

在Default.aspx.cs页面中,默认会存在Page_Load方法,定义如下:

        protected void Page_Load(object sender, EventArgs e)
        {
            this.LiLoad.Text = "这是在页面Load事件";
        }

页面被请求,在页面加载的时候会执行该方法。那么这个方法为什么会在页面加载的时候执行,我们并没有把它注册给页面相应的事件。页面的事件也有很多,我们列出一些重要的页面事件看一下:

在Page类中存在下面的事件,Page类是页面的基类:

        public event EventHandler InitComplete;

        public event EventHandler LoadComplete;

        public event EventHandler PreInit;

        public event EventHandler PreLoad;

        public event EventHandler PreRenderComplete;

        public event EventHandler SaveStateComplete;

在Control类中存在下面的事件,Control类是Page类的基类:

        public event EventHandler DataBinding;

        public event EventHandler Disposed;

        public event EventHandler Init;

        public event EventHandler Load;

        public event EventHandler PreRender;

我们对这其中比较关注的事件提取出来,并根据事件的执行顺序来排序:

PreInit:在页面的初始化阶段开始时引发

Init:在页面的初始化时引发

InitComplete:在页面的初始化结束时引发

PreLoad:在页面的加载阶段开始时引发   

Load:在页面的加载时引发

LoadComplete:在页面的加载结束时引发

PreRender:在页面即将被呈现时引发

我们看到页面事件有很多,主要来研究Init和Load这两个事件。在Default.aspx.cs页面中,添加Page_Init方法,定义如下:

        protected void Page_Init(object sender, EventArgs e)
        {
            this.LiInit.Text = "这是在页面Init事件";
        }

那么还是回到上面的问题,为什么会在页面请求之后执行Page_Init、Page_Load方法?

原因是:ASP.NET中AutoEventWireup="true",使页面与某些特殊的事件方法绑定,自动识别这些具有特定名称的方法,而不需要进行注册事件。
这些特定名称包括:Page_Init, Page_Load等。这里就说明:Init事件会自动与Page_Init方法绑定,Load事件自动与Page_Load方法绑定。当然这些都是AutoEventWireup="true"的功劳,当我们AutoEventWireup="false"的时候,再次请求页面的时候,Page_Init、Page_Load方法是不会被执行的。那么我们可以显示注册事件:

      protected override void OnInit(EventArgs e)
        {
            this.Init += new EventHandler(this.Page_Init);
            base.OnInit(e);
        }
        protected override void OnLoad(EventArgs e)
        {
            this.Load += new EventHandler(this.Page_Load);
            base.OnLoad(e);
        }

那么OnInit和OnLoad又是什么来头呢?它们是Control类中定义的虚方法,所以我们可以在它的子类里面进行重写。
看ASP.NET 的注释是这样描写的:
OnInit:引发 System.Web.UI.Control.Init 的事件。
OnLoad:引发 System.Web.UI.Control.Load 的事件。

很好啊,我们在这边对它们重写,并注册事件合情合理。
我们把对Init注册事件语句放到OnLoad方法中,把对Load注册事件语句放到OnInit方法中,是两个处理的内容交换一下看看会有什么结果:

        protected override void OnInit(EventArgs e)
        {
            this.Load += new EventHandler(this.Page_Load);
            base.OnInit(e);
        }
        protected override void OnLoad(EventArgs e)
        {
            this.Init += new EventHandler(this.Page_Init);
            base.OnLoad(e);
        }

我们请求页面发现:在OnInit方法中对Load注册事件执行了,在OnLoad方法中对Init注册事件并没有执行。原因是在执行OnInit方法之后,就表示Init事件已经响应完成,在之后再对Init事件注册方法,并不会得到调用。而在OnInit方法中对Load注册事件的时候,Load事件并没有开始触发,这个时候对Load注册事件是有效的。所以现在我们很多时候,都形成了一种规范,只会重写OnInit方法,不重写OnLoad方法,也能完成我们的需求。所以在有些框架里面看不到OnLoad方法就是这样形成的。我们把Default.aspx.cs页面调整成:

        protected override void OnInit(EventArgs e)
        {
            this.Init += new EventHandler(this.Page_Init);
            this.Load += new EventHandler(this.Page_Load);
            base.OnInit(e);
        }

很明显我们觉得不需要Page_Init和Page_Load方法,我们再次调整为:

        protected override void OnInit(EventArgs e)
        {
            this.LiInit.Text = "这是在页面Init事件";
            this.LiLoad.Text = "这是在页面Load事件";
            base.OnInit(e);
        }

我附上调试的源码Default.aspx:

复制代码
<%@ Page Language="C#" AutoEventWireup="false" CodeBehind="Default.aspx.cs" Inherits="AspxEventsModel._Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <asp:Literal ID="LiInit" runat="server"></asp:Literal>
    <br />
    <asp:Literal ID="LiLoad" runat="server"></asp:Literal>
</body>
</html>
复制代码

Default.aspx.cs:

复制代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace AspxEventsModel
{
    public partial class _Default : System.Web.UI.Page
    {
        protected override void OnInit(EventArgs e)
        {
            this.LiInit.Text = "这是在页面Init事件";
            this.LiLoad.Text = "这是在页面Load事件";
            //this.Init += new EventHandler(this.Page_Init);
            
//this.Load += new EventHandler(this.Page_Load);
            base.OnInit(e);
        }
        //protected override void OnLoad(EventArgs e)
        
//{
        
//    this.Load += new EventHandler(this.Page_Load);
        
//    //this.Init += new EventHandler(this.Page_Init);
        
//    base.OnLoad(e);
        
//}
        
//protected void Page_Init(object sender, EventArgs e)
        
//{
        
//    this.LiInit.Text = "这是在页面Init事件";
        
//}
        
//protected void Page_Load(object sender, EventArgs e)
        
//{
        
//    this.LiLoad.Text = "这是在页面Load事件";
        
//}
    }
}
复制代码

在这里只是抛砖引玉的简单说明了一下,深究下去远远不止这些。好了,赶快自己动手试试吧

asp.net页面的AutoEventWireup="true"属性设置

阅读更多

扫码向博主提问

躬行者

非学,无以致疑;非问,无以广识
  • 擅长领域:
  • PHP
  • Linux运维
  • Mysql
  • 小程序开发
  • Python
去开通我的Chat快问
换一批

没有更多推荐了,返回首页