5. 应用程序 [SimuPaie] – 版本 2 – AJAX / ASP.NET
5.1. Introduction
AJAX(异步 JavaScript 和 XML)技术整合了一系列技术:
- JavaScript:在浏览器中显示的 HTML 页面可嵌入 JavaScript 代码。 如果用户未在浏览器中禁用 JavaScript 代码的执行,该代码将由浏览器执行。该技术自万维网诞生之初便已出现,并自 2005 年起因 AJAX 而重新受到关注。
- DOM:文档对象模型(Document Object Model)。嵌入在HTML页面中的JavaScript代码,能够以对象树的形式访问该文档,即DOM。 文档中的每个元素(输入字段、命名过的 <div> 标签、<select> 标签等)都由树中的一个节点表示。 JavaScript 代码可以通过修改 DOM 来更改显示的文档。例如,它可以通过代表该输入字段的 DOM 节点,来更改输入字段中显示的文本。
AJAX 使用 JavaScript 在后台进行浏览器与服务器之间的交互。 当发生点击按钮等事件时,浏览器将执行 JavaScript 代码,向服务器发送 HTTP 请求。该请求将包含指示服务器执行操作的参数,服务器随后将执行所请求的操作。 服务器将向浏览器发送一个名为 HTTP 的数据流作为响应,其中包含用于部分更新当前显示页面的数据。该更新将通过文档中的 DOM 以及文档中嵌入的 JavaScript 代码的执行来实现。 服务器返回的数据可以采用多种格式:XML、HTML、JSON、未格式化文本等。
该技术的优势在于对显示文档进行部分更新。这意味着:
- 客户端与服务器之间传输的数据更少,响应速度因此更快
- 图形界面操作更流畅,因为用户的操作不会导致页面完全重新加载。
在网络传输速度较快的内联网环境中,AJAX 能够创建行为模式接近传统 Windows 界面的 Web 应用程序。实际上,我们可以处理诸如列表中选项变更等事件,并立即对页面进行部分刷新以反映该选项变更。 页面无需完全重新加载,这让用户获得了与 Windows 应用程序相似的流畅体验。对于响应时间可能较长的互联网应用程序,AJAX 技术依然适用,但流畅度体验取决于网络状况。
AJAX的主要难点在于JavaScript语言。该语言诞生于万维网的早期,
- 但它并不适合进行面向对象的编程。例如,它并非一种类型化语言,无需声明所处理数据的类型,这使其更接近Perl或PHP等语言。
- 它没有被所有浏览器普遍接受的标准。每个浏览器都有其专有的“JavaScript”扩展,这导致为 IE 编写的 JavaScript 代码可能无法在 Mozilla Firefox 中运行,反之亦然。
- 它难以调试,因为浏览器并未提供高效的工具来调试其执行的JavaScript代码。
正是由于JavaScript存在这些缺陷,在AJAX出现之前,它鲜少被使用。一旦人们意识到在后台执行JavaScript代码的价值——即向Web服务器发送HTTP请求,并利用服务器的响应来实现 借助DOM实现显示文档的部分更新,开发团队便着手投入工作,并推出了无需开发者编写JavaScript代码即可实现AJAX功能的框架。 为此,开发了能够适配客户端浏览器的JavaScript库。将JavaScript代码插入发送至浏览器的HTML页面是在服务器端完成的,具体技术实现因所使用的AJAX框架而异。 目前已有适用于 Java、.NET、PHP、Ruby 等语言的 Ajax 框架。AJAX 已集成于 Visual Web Developer 2008 中。
5.2. [web-ui-ajax] 层的 Visual Web Developer 项目
新版本是通过复制旧版本获得的。仅对 [Default.aspx] 页面进行修改。
![]() |
- 在 [1] 中,使用 Windows 资源管理器复制 [pam-v1-adonet] 项目文件夹,并将其重命名为 [pam-v2-adonet-ajax]。 然后使用 Visual Web Developer,打开该新文件夹 [2] 中的项目(文件 / 打开项目)
- ,将其重命名为
![]() |
- 在新项目的属性中,将程序集名称 [4] 以及默认命名空间 [5] 进行修改。
完成上述操作后,在文件 [Default.aspx, Default.aspx.cs, Default.aspx.designer.cs, Global.asax, Global.asax.cs] 中,将命名空间 [pam_v1] 替换为 [pam_v2],以与默认命名空间保持一致。 例如,[Default.aspx] [6] 变为:
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="pam_v2._Default" %>
...
页面 [Default.aspx] 将按以下方式修改:
![]() |
- 在表单 [Default.aspx] 中添加 Ajax 组件(参见上文的 [2])。
- 2A:所有 AJAX 项目均需使用 <asp:ScriptManager> 组件
- 2B:<asp:UpdatePanel>组件用于在用户执行POST操作时限定需要刷新区域。该组件可避免页面完全重新加载。
- 2C:<asp:UpdateProgress> 组件用于在更新期间显示文本或图像,以提醒用户,如下所示:
![]() |
- (续)
- 2D:一个名为 LabelHeureLoad 的 Label 类型,用于显示页面事件处理程序 Load 的执行时间。
- 2E: 一个名为 LabelHeureSalaire 的 Label 类型事件,用于显示 [Salaire] 按钮上 Click 事件处理程序的执行时间。 我们希望展示的是,点击按钮 [Salaire] 时,Ajax 不会重新加载整个页面。前面的屏幕截图展示了这一点,其中两个 Labels 显示了两个不同的时间。
之前对表单的 Ajax 化处理可直接在 [Default.aspx] 的源代码中完成,方法是添加 Ajax 扩展标签:
...
<body style="text-align: left" bgcolor="#ffccff">
<h3>
Feuille de salaire
<asp:Label ID="LabelHeureLoad" runat="server" BackColor="#C0C000"></asp:Label></h3>
<hr />
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server" EnablePartialRendering="true" />
<asp:UpdatePanel runat="server" ID="UpdatePanelPam" UpdateMode="Conditional">
<ContentTemplate>
<div>
<table>
<tr>
...
<tr>
<td>
<asp:DropDownList ID="ComboBoxEmployes" runat="server">
</asp:DropDownList></td>
<td>
<asp:TextBox ID="TextBoxHeures" runat="server" EnableViewState="False">
</asp:TextBox></td>
<td>
<asp:TextBox ID="TextBoxJours" runat="server" EnableViewState="False">
</asp:TextBox></td>
<td>
<asp:Button ID="ButtonSalaire" runat="server" Text="Salaire" CausesValidation="False" /></td>
<td> <asp:UpdateProgress ID="UpdateProgress1" runat="server">
<ProgressTemplate>
<img src="images/indicator.gif" />
<asp:Label ID="Label5" runat="server" BackColor="#FF8000" EnableViewState="False"
Text="Calcul en cours. Patientez ...."></asp:Label>
</ProgressTemplate>
</asp:UpdateProgress>
<asp:Label ID="LabelHeureSalaire" runat="server" BackColor="#C0C000"></asp:Label></td>
</tr>
<tr>
...
</tr>
</table>
</div>
<br />
....
<table>
<tr>
<td>
Salaire net à payer :
</td>
<td align="center" bgcolor="#C0C000" height="20px">
<asp:Label ID="LabelSN" runat="server" EnableViewState="False"></asp:Label></td>
</tr>
</table>
</asp:Panel>
</ContentTemplate>
</asp:UpdatePanel>
</form>
</body>
</html>
- 第 8 行:所有经过 Ajax 化的表单都必须包含 <asp:ScriptManager> 标签。正是这个标签使得新 Ajax 组件得以使用:
![]() |
- 双击上方的 [ScriptManager] 组件即可获得 <asp:ScriptManager> 标签。 请务必确认该标签位于源代码的 <form> 标签内。第 8 行中的 [EnablePartialRendering= "true "] 属性默认缺失。由于其默认值为 "true",因此并非必需。
- 第 9 行:<asp:UpdatePanel> 标签用于在页面部分刷新时,限定需要更新的页面区域。 [UpdateMode="Conditional"] 属性表示该区域仅在区域内某个组件触发 AJAX 事件时才需更新。另一个属性值为 [UpdateMode="Always"],这是默认值。 使用此属性时,即使发生的 Ajax 事件源自另一个区域 UpdatePanel 的组件,区域 UpdatePanel 仍会系统性地被更新。通常情况下,这种行为是不希望出现的。
<asp:UpdatePanel> 标签支持两个子标签:<ContentTemplate> 和 <Triggers>。
- 第 10 行和第 53 行的 <asp:ContentTemplate> 标签界定了页面中需要进行部分更新的区域。
- 第 27-33 行:一个 Ajax 组件 <asp:UpdateProgress>,用于在页面更新期间显示文本。 例如,点击 [Salaire] 按钮将触发后台的 POST 操作。此时浏览器不会显示沙漏图标,用户因此可能误以为可以继续使用表单。 <asp:UpdateProgress> 标签可显示一条提示文本,告知页面正在更新。也可以显示一张图片。在此,我们显示了一张动画图片(第 29 行)以及一段文本(第 30-31 行):
![]() |
- 第28-32行:<ProgressTemplate>标签界定了在UpdatePanel区域更新期间将显示的内容,该区域内包含UpdateProgress标签。
- 第29-31行:在UpdatePanel区域更新期间将显示的动画图像和文本。
- 第 5 行:标签 LabelHeureLoad 被放置在 AJAX 区域之外
- 第 34 行:标签 LabelHeureSalaire 被放置在 AJAX 区域内
页面 [Default.aspx.cs]( )的代码则按以下方式进行调整:
protected void Page_Load(object sender, System.EventArgs e)
{
// 每次页面加载的时间
LabelHeureLoad.Text = DateTime.Now.ToString("hh:mm:ss");
// 初始请求处理
if (!IsPostBack)
{
....
}
- 第 4 行:更新页面加载时间
protected void ButtonSalaire_Click(object sender, System.EventArgs e)
{
// 工资计算时间
LabelHeureSalaire.Text = DateTime.Now.ToString("hh:mm:ss");
// 正在验证数据
....
}
- 第 4 行:更新工资计算时间
要完成页面 [Default.aspx],我们需要包含由该页面源代码第 4 行引用的动画图片:
<td>
<asp:UpdateProgress ID="UpdateProgress1" runat="server">
<ProgressTemplate>
<img src="images/indicator.gif" />
<asp:Label ID="Label5" runat="server" BackColor="#FF8000" EnableViewState="False"
Text="Calcul en cours. Patientez ...."></asp:Label>
</ProgressTemplate>
</asp:UpdateProgress>
<asp:Label ID="LabelHeureSalaire" runat="server" BackColor="#C0C000"></asp:Label>
</td>
使用 Windows 资源管理器,我们将文件 [images/indicator.gif] 添加到项目文件夹 [1] 中:
![]() |
- 在 [2] 中,显示项目中的所有文件
- 在 [3] 中,文件夹 [images]
- 在 [4] 中,将文件夹 [images] 纳入项目
![]() |
- 转换为 [5],文件夹 [images] 已包含在项目中
- 在 [6] 中,隐藏不属于该项目的文件
- 在 [7] 中,新项目
5.3. Ajax 解决方案测试
当请求运行项目(CTRL-F5)时,将显示以下页面:
![]() |
- 在 [1] 中,页面加载时间
请进行测试,并确认按钮 [Salaire] 不会导致页面完全重新加载。 您可以通过 [Salaire] 和 [2] 按钮点击处理时间(显示的时间)来观察这一点,该时间与页面 [3] 的初始加载时间并不相同:
![]() |
将组件 ScriptManager1 的属性 EnablePartialRendering 设置为 False 后重新进行测试:
![]() |
此时可观察到页面表现为非Ajax模式。点击按钮[Salaire]时,页面会完全重新加载。请使用其他浏览器重新进行测试。 进行多浏览器测试旨在验证由服务器组件 ASP / AJAX 生成的 JavaScript 能否被不同浏览器正确解析。
最后,让我们重点说明 <asp:UpdateProgress> 标签的作用。在 [Default.aspx.cs] 的 [ButtonSalaire_Click] 存储过程代码中,添加一条将存储过程暂停 3 秒的语句:
using System.Threading;
...
protected void ButtonSalaire_Click(object sender, System.EventArgs e)
{
// 工资计算时间
LabelHeureSalaire.Text = DateTime.Now.ToString("hh:mm:ss");
// 等待
Thread.Sleep(3000);
// 正在验证数据
....
}
第 8 行使执行 [ButtonSalaire_Click] 过程的线程等待 5 秒。 完成上述操作后,重新进行测试(在将组件 ScriptManager1 的属性 EnablePartialRendering 设为 True 之后)。这次,在计算工资期间,我们可以看到 [UpdateProgress] 的文本以及动画图像:
![]() |
5.4. Conclusion
前文的研究表明,现有 ASP.NET 应用程序是可以实现 AJAX 化的。 AJAX 的扩展功能比刚才所见的内容更进一步。欢迎读者访问 [http://ajax.asp.net] 网站。











