在今天我主要要介绍的有如下知识点:
Page类介绍
Page的生命周期
IsPostBack属性
ClientScriptManager类
回调技术(CallBack)
Page类介绍
asp.net有时候也被成为WebForm,因为开发一个asp.net页面就像开发一个WinFrom窗体一样,我们同样可以采用拖拽控件、双击产生相关处理代码的方法。在asp.net中,创建一个页面可以采用两种模型。
单页模型
用Dreamweaver创建的asp.net页面就是单页模型,当然利用Visual Studio 2005也能创建单页模型,不过在Visual Studio 2005中创建的页面默认不是单页模型,要想在Visual Studio 2005创建单页模型的网页如下:
注意确保“将代码放在单独的文件中”选项处于未选中状态,默认情况下这个选项是处于选中状态的。这样就创建了单页模型的网页。
此时的页面代码如下:
- <%@ Page Language="C#" %>
-
-
-
- <script runat="server">
- script>
-
- <html xmlns="http://www.w3.org/1999/xhtml" >
- <head runat="server">
- <title>无标题页title>
- head>
- <body>
- <form id="form1" runat="server">
- <div>
-
- div>
- form>
- body>
- html>
注意在页面中有这样一句代码:
- <script runat="server">
- script>
这句代码与普通javascript语句块不同的是有一个runat="server"属性,表示这里的代码是在服务器上运行的C#代码。切换到设计视图,然后双击页面,然后这部分会变成如下的样子:
- <script runat="server">
-
- protected void Page_Load(object sender, EventArgs e)
- {
-
- }
- script>
其中Page_Load就是页面加载的时候在服务器上运行的方法。
单页模型的特点是HTML标记、控件代码及服务器端运行的C#代码全部包含在一个aspx页面中,Web服务器第一次运行该页面的时候会将这个页面生成一个类文件,对于上面的Index.aspx页面,会生成ASP.Index_aspx的类,然后再将这个ASP.Index_aspx类编译成IL代码,Web服务器通过CLR(Common Language Runtime,通用语言运行环境)运行相应的IL代码。
单页模型的缺点是页面和代码混在一起,维护起来较为麻烦。
代码页面分离模式
代码页面模式就是将页的标记(HTML代码)和服务器端元素放在.aspx页面中,而也代码在位于一个.aspx.cs中。采用默认方式创建的aspx网页就是这种方式。
下面就是一个采用代码页面分离模式创建的Home.aspx页面的代码:
- <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Home.aspx.cs" Inherits="Home" %>
-
-
-
- <html xmlns="http://www.w3.org/1999/xhtml" >
- <head runat="server">
- <title>无标题页title>
- head>
- <body>
- <form id="form1" runat="server">
- <div>
-
- div>
- form>
- body>
- html>
其对应的页代码是:
- using System;
- using System.Data;
- using System.Configuration;
- using System.Collections;
- using System.Web;
- using System.Web.Security;
- using System.Web.UI;
- using System.Web.UI.WebControls;
- using System.Web.UI.WebControls.WebParts;
- using System.Web.UI.HtmlControls;
-
- public partial class Home : System.Web.UI.Page
- {
- protected void Page_Load(object sender, EventArgs e)
- {
-
- }
- }
首先要关注的aspx的头部分代码:
- <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Home.aspx.cs" Inherits="Home" %>
@Page是一个页面指令,在这里Language="C#"指明了当前页面采用的后台代码是C#语言,CodeFile="Home.aspx.cs"表示这个页面对应的页代码文件是Home.aspx.cs这个文件,Inherits="Home"表示当前aspx页继承自Home这个类。
现在再关注一下页代码文件声明:
- public partial class Home : System.Web.UI.Page
从这部分代码可以看出Home类是继承自System.Web.UI.Page类的。注意这里还有一个C#2.0的关键字partial,这个关键字表示当前代码是一个局部类,以表示这个类是构成整个Web页面窗体的一部分。Web服务器运行这个页面的时候最终会将aspx页面和对应的页代码编译成一个类文件,然后生成IL代码。
代码页面分离模式的好处是页面展示部分和逻辑控制部分的代码分离开来,便于管理和维护,这也是微软推荐的开发方式。
asp.net页面的声明周期
asp.net页面运行的时候将经历一个声明周期,这个生命周期中会进行一系列的操作,调用一系列的方法。了解asp.net页面的生命周期对于精确控制页面的控件呈现方式和行为非常重要。
一般说来一个常规页面要经历如下几个生命周期阶段:
| 阶段 |
说明 |
| 页请求 |
页请求发生在页生命周期开始之前。用户请求页时,ASP.NET 将确定是否需要分析和编译页(从而开始页的生命周期),或者是否可以在不运行页的情况下发送页的缓存版本以进行响应。 |
| 开始 |
在开始阶段,将设置页属性,如 Request 和 Response。在此阶段,页还将确定请求是回发请求还是新请求,并设置 IsPostBack 属性。此外,在开始阶段期间,还将设置页的 UICulture 属性。 |
| 页初始化 |
页初始化期间,可以使用页中的控件,并将设置每个控件的 UniqueID 属性。此外,任何主题都将应用于页。如果当前请求是回发请求,则回发数据尚未加载,并且控件属性值尚未还原为视图状态中的值。 |
| 加载 |
加载期间,如果当前请求是回发请求,则将使用从视图状态和控件状态恢复的信息加载控件属性。 |
| 验证 |
在验证期间,将调用所有验证程序控件的 Validate 方法,此方法将设置各个验证程序控件和页的 IsValid 属性。 |
| 回发事件处理 |
如果请求是回发请求,则将调用所有事件处理程序。 |
| 呈现 |
在呈现期间,视图状态将被保存到页,然后页将调用每个控件,以将其呈现的输出提供给页的 Response 属性的 OutputStream。 |
| 卸载 |
完全呈现页、将页发送至客户端并准备丢弃时,将调用卸载。此时,将卸载页属性(如 Response 和 Request)并执行清理。 |
在页的生命周期中,一般会有如下事件:
| 页事件 |
典型使用 |
| Page_PreInit |
使用 IsPostBack 属性确定是否是第一次处理该页。 创建或重新创建动态控件。 动态设置主控页。 动态设置 Theme 属性。 读取或设置配置文件属性值。 注意:如果请求是回发请求,则控件的值尚未从视图状态还原。如果在此阶段设置控件属性,则其值可能会在下一阶段被改写。 |
| Page_Init |
读取或初始化控件属性。 |
| Page_Load |
读取和更新控件属性。 |
| Control events |
执行特定于应用程序的处理: 如果页包含验证程序控件,请在执行任何处理之前检查页和各个验证控件的 IsValid 属性。 处理特定事件,如 Button 控件的 Click 事件。 |
| Page_PreRender |
对页的内容进行最后更改。 |
| Page_Unload |
执行最后的清理工作,可能包括: 关闭打开的文件和数据库连接。 完成日志记录或其他特定于请求的任务。 |
需要注意的是,每个asp.net控件也有与asp.net类似的生命周期,如果aspx页面中包含有asp.net服务器控件,那么在调用页面的方法时也会调用控件的相关方法。
另外,Web应用程序是无状态的。每次请求一个新网页或者刷新页面服务器都会创建一个当前页的新实例,这就意味着无法获取页面的以前的信息,如果确实需要这么做,需要采用额外的机制。
我们将刚才新建的Index.aspx页面中添加代码,如下:
- <%@ Page Language="C#" %>
-
-
-
- <script runat="server">
- string date;
- protected void Page_Load(object sender, EventArgs e)
- {
- if (date == null)//如果date为空则设置为当前时间的字符串形式
- {
- date = DateTime.Now.ToString();
- }
- Response.Write("当前时间:"+date);
- }
- script>
-
- <html xmlns="http://www.w3.org/1999/xhtml" >
- <head runat="server">
- <title>无标题页title>
- head>
- <body>
- <form id="form1" runat="server">
- <div>
-
- div>
- form>
- body>
- html>
按照正常理解,第一次运行的时候date字符串为null,会被设置成系统当前的字符串表示形式,并且输出,再次刷新的时候date字符串不再为空,会依然输出刚才的时间字符串,但是结果却不是这样。第一次运行的结果:

刷新页面之后的结果:

这就证明了即使是刷新当前页也会重新生成一个当前页面的实例,因为只有在生成页面新实例的情况下date字符串变量才为空,才会被重新设置值。
IsPostBack属性
Page类有一个IsPostBack属性,这个属性用来指示当前页面是第一次加载还是响应了页面上某个控件的服务器事件导致回发而加载。
这次我们继续对Index.aspx页面添加代码,在页面中增加了一个Button控件,如下:
- <%@ Page Language="C#" %>
-
-
-
- <script runat="server">
- string date;
- protected void Page_Load(object sender, EventArgs e)
- {
- if (date == null)//如果date为空则设置为当前时间的字符串形式
- {
- date = DateTime.Now.ToString();
- }
- Response.Write("当前时间:"+date);
- if (!Page.IsPostBack)
- {
- Response.Write("第一次加载。");
- }
- else
- {
- Response.Write("响应客户端回发而加载。");
- }
- }
-
- protected void btnOK_Click(object sender, EventArgs e)
- {
-
- }
- script>
-
- <html xmlns="http://www.w3.org/1999/xhtml" >
- <head runat="server">
- <title>无标题页title>
- head>
- <body>
- <form id="form1" runat="server">
- <div>
- <asp:Button ID="btnOK" runat="server" OnClick="btnOK_Click" Text="提交" />div>
- form>
- body>
- html>
页面第一次运行的结果:
按一下F5刷新页面的结果:
点击一下“提交”按钮之后的结果:
由此可见每次打开一个页面和刷新一个页面效果都是一样的,只有响应客户端回发时IsPostBack属性才是true。了解这个属性和服务器采用了一种机制来“记录”服务器控件的状态这种做法(其实利用了ViewState和ControlState机制,这部分后续文章中会讲到)对于将来数据绑定会有很大作用。
动态输出javascript脚本
对于Index.aspx页面上面的执行情况,我们看到了满意的结果。我们再来看一下这个页面在客户端生成的HTML代码,在浏览器窗口打开的页面点鼠标右键,然后选择“查看源文件”,HTML代码如下:
- 当前时间:2008-9-21 0:04:33响应客户端回发而加载。
-
-
-
-
-
- <html xmlns="http://www.w3.org/1999/xhtml" >
- <head><title>
- 无标题页
- title>head>
- <body>
- <form name="form1" method="post" action="Index.aspx" id="form1">
- <div>
- <input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="/wEPDwUKMTY3NzE5MjIyMGRkD2VvJFADDdEHh4W9UfAyzIvI3ss=" />
- div>
-
- <div>
- <input type="submit" name="btnOK" value="提交" id="btnOK" />div>
-
- <div>
-
- <input type="hidden" name="__EVENTVALIDATION" id="__EVENTVALIDATION" value="/wEWAgL8vZamCQLdkpmPAeM33vfm1ARVNKdKAoq5+eQdFI1J" />
- div>form>
- body>
- html>
我们会看到“当前时间:2008-9-21 0:04:33响应客户端回发而加载。”这句话位于标记之外。在第一夜时候就提到过,asp.net页面是满足XML标准的HTML语言,但是通过在Page_Load事件中利用Response属性会将文字输出在标记之外,不符合XHTML标准。这对于普通页面来说也许并无大碍,但是如果在频繁输出javascript脚本的网页中,可能会对网页的客户端执行效果产生影响。因为javascript脚本块在客户端调用方法之前还是客户端调用方法之后效果可能会不一样。
下面在Home窗体的Page_Load事件中添加代码,如下:
- using System;
- using System.Data;
- using System.Configuration;
- using System.Collections;
- using System.Web;
- using System.Web.Security;
- using System.Web.UI;
- using System.Web.UI.WebControls;
- using System.Web.UI.WebControls.WebParts;
- using System.Web.UI.HtmlControls;
-
- public partial class Home : System.Web.UI.Page
- {
- protected void Page_Load(object sender, EventArgs e)
- {
- if (!Page.IsPostBack)
- {
- Response.Write("");
- }
- }
- }
这样每次运行Home.aspx页面的时候都会弹出一个对话框,如下图:

这不是我们所关心的,我们关注的是生成的HTML代码,如下:
- <script language='javascript'>alert('2008-9-21 0:22:52')script>
-
-
-
- <html xmlns="http://www.w3.org/1999/xhtml" >
- <head><title>
- 无标题页
- title>head>
- <body>
- <form name="form1" method="post" action="Home.aspx" id="form1">
- <div>
- <input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="/wEPDwUJNzgzNDMwNTMzZGTB6tgIyCoS2q3pZeKmhFwC24pQzw==" />
- div>
-
- <div>
-
- div>
- form>
- body>
- html>
可以看见输出的javascript代码在标记之外。
在Page类中有一个ClientScript属性,它是ClientScriptManager的实例,这个类是在asp.net2.0中新增的。ClientScriptManager有如下几个常用方法:
RegisterClientScriptBlock方法:向 Page 对象注册客户端脚本。
RegisterStartupScript方法:向 Page 对象注册启动脚本。
ClientScriptManager类通过键string和Type来唯一标识脚本。具有相同类型的键和Type的脚本识为同一脚本。
下面对Home窗体的Page_Load事件中输入如下代码:
- using System;
- using System.Data;
- using System.Configuration;
- using System.Collections;
- using System.Web;
- using System.Web.Security;
- using System.Web.UI;
- using System.Web.UI.WebControls;
- using System.Web.UI.WebControls.WebParts;
- using System.Web.UI.HtmlControls;
-
- public partial class Home : System.Web.UI.Page
- {
- protected void Page_Load(object sender, EventArgs e)
- {
-
- if (!ClientScript.IsClientScriptBlockRegistered(this.GetType(), "ClientScriptBlock"))
- {
- ClientScript.RegisterClientScriptBlock(this.GetType(), "ClientScriptBlock", "");
- }
-
- if (!ClientScript.IsStartupScriptRegistered(this.GetType(), "StartupScript"))
- {
- ClientScript.RegisterStartupScript(this.GetType(), "StartupScript", "");
- }
-
- }
- }
执行该页面时,会弹出两个提示窗口,生成的HTML代码如下:
-
-
-
- <html xmlns="http://www.w3.org/1999/xhtml" >
- <head><title>
- 无标题页
- title>head>
- <body>
- <form name="form1" method="post" action="Home.aspx" id="form1">
- <div>
- <input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="/wEPDwUJNzgzNDMwNTMzZGTB6tgIyCoS2q3pZeKmhFwC24pQzw==" />
- div>
-
- <script language='javascript'>alert('ClientScriptBlock')script>
- <div>
- div>
-
- <script language='javascript'>alert('StartupScript')script>form>
- body>
- html>
可以看出上面的两个方法输出的javascript脚本都在
标记之内,不会破环文章的结构,而且RegisterClientScriptBlock方法输出的javascript脚本代码块靠近
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/12639172/viewspace-466029/
,如需转载,请注明出处,否则将追究法律责任。