Skip to content

5. [SimuPaie] 应用程序 – 版本 2 – AJAX / ASP.NET

5.1. 简介

AJAX(异步 JavaScript 和 XML)技术整合了一系列技术:

  • JavaScript:在浏览器中显示的 HTML 页面可以嵌入 JavaScript 代码。如果用户未在浏览器中禁用 JavaScript 执行,该代码将由浏览器执行。这项技术自万维网早期便已存在,并得益于 AJAX,自 2005 年以来重新受到关注。
  • DOM:文档对象模型。嵌入在 HTML 页面中的 JavaScript 代码可以通过对象树(即 DOM)的形式访问文档。文档中的每个元素(输入字段、命名的 div 标签、select 标签等)在树中都由一个节点表示。JavaScript 代码可以通过修改 DOM 来改变显示的文档。例如,它可以通过代表该字段的 DOM 节点来更改输入字段中显示的文本。

AJAX利用JavaScript在后台进行浏览器与服务器之间的交互。当响应按钮点击等事件时,浏览器会执行JavaScript代码,向服务器发送HTTP请求。该请求包含参数,用于告知服务器应执行的操作。 随后,服务器执行所请求的操作。作为响应,它向浏览器发送一个包含数据的 HTTP 数据流,从而实现当前显示页面的局部更新。这一过程通过文档的 DOM 以及文档中嵌入的 JavaScript 代码的执行来完成。服务器返回的数据可以采用多种格式:XML、HTML、JSON、纯文本等。

该技术的优势在于对显示文档的局部更新。这意味着:

  • 客户端与服务器之间交换的数据更少,从而获得更快的响应
  • 图形界面使用更流畅,因为用户操作不会触发整页重新加载。

在网络传输速度较快的内联网环境中,AJAX 能够创建行为与传统 Windows 界面相似的 Web 应用程序。例如,当列表中的选项发生变化时,系统可以立即对页面进行部分刷新以反映该变化。 页面无需完全重新加载这一特性,为用户带来了与 Windows 应用程序相同的流畅体验。对于响应时间可能较长的 Web 应用程序,AJAX 技术依然适用,但用户感知到的流畅度取决于网络性能。

AJAX面临的主要挑战在于JavaScript语言。该语言诞生于万维网的早期,

  • 它被证明不适合面向对象编程。例如,它不是一种类型化语言。你无需声明所操作数据的类型。在这方面,它与Perl或PHP等语言相似。
  • 目前尚无所有浏览器都认可的标准。每个浏览器都有自己专有的 JavaScript 扩展,这意味着为 Internet Explorer 编写的 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] 打开项目(文件 / 打开项目)
  • 在 [3] 中,将其重命名为
  • 在新项目的属性中,修改程序集名称 [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 不会重新加载整个页面。如前面的屏幕截图所示,两个 Label 中显示了两个不同的时间。

上述表单的 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>
          &nbsp;</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>,用于在页面更新过程中显示文本。例如,单击 [Salary] 按钮会在后台触发一个 POST 请求。浏览器不会显示沙漏图标,因此用户可能会继续使用该表单。 <asp:UpdateProgress> 标签会显示文本,提示页面正在更新。也可以显示图片。此处显示了一个动画图片(第 29 行)和文本(第 30–31 行):
 
  • 第 28–32 行:<ProgressTemplate> 标签界定了在包含 UpdateProgress 标签的 UpdatePanel 更新期间将显示的内容。
  • 第 29–31 行:在 UpdatePanel 更新期间将显示的动画图像和文本。
  • 第 5 行:LabelHeureLoad 标签位于 AJAX 启用区域之外
  • 第 34 行:LabelHeureSalaire 标签位于 AJAX 启用区域内

[ Default.aspx.cs] 页面的代码更改如下:


    protected void Page_Load(object sender, System.EventArgs e)
    {
        // time of each page load
        LabelHeureLoad.Text = DateTime.Now.ToString("hh:mm:ss");
        // initial request processing
        if (!IsPostBack)
        {
....
}
  • 第 4 行:更新页面加载时间

   protected void ButtonSalaire_Click(object sender, System.EventArgs e)
    {
        // hourly wage calculation
        LabelHeureSalaire.Text = DateTime.Now.ToString("hh:mm:ss");
        // data verification
....
}
  • 第 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] 中,页面加载时间

测试应用程序,并验证[Salary]按钮不会导致页面完全重新加载。您可以通过比较[Salary]按钮点击处理所显示的时间[2](该时间与页面初始加载时间[3]不同)来观察这一点:

将 ScriptManager1 组件的 EnablePartialRendering 属性设置为 False,然后重复上述测试:

  

请注意,当前的行为与非 AJAX 页面相似。点击 [Salary] 按钮时,页面会完全重新加载。请使用其他浏览器重复进行测试。跨浏览器测试的目的是验证由 ASP/AJAX 服务器组件生成的 JavaScript 代码能否被不同浏览器正确解释。

最后,让我们重点说明 <asp:UpdateProgress> 标签的作用。在 [Default.aspx.cs] 文件中 [ButtonSalaire_Click] 过程的代码里,添加一条将过程暂停 3 秒的语句:


using System.Threading;
   ...
protected void ButtonSalaire_Click(object sender, System.EventArgs e)
    {
        // hourly wage calculation
        LabelHeureSalaire.Text = DateTime.Now.ToString("hh:mm:ss");
        // waiting 
        Thread.Sleep(3000);
        // data verification
....
}

第 8 行代码会让执行 [ButtonSalaire_Click] 过程的线程等待 5 秒。完成后,让我们再次运行测试(在此之前,需将 ScriptManager1 组件的 EnablePartialRendering 属性设置为 True)。这次,在计算工资的过程中,我们会看到 [UpdateProgress] 中的文本以及动画图像:

Image

5.4. 结论

前面的研究向我们展示了,可以在现有的 ASP.NET 应用程序中添加 AJAX 功能。ASP.NET AJAX 扩展的功能远不止我们刚才所见。欢迎读者访问网站 [http://ajax.asp.net]。