为 DataList 控件的编辑界面添加验证控件

本文档是 Visual C# 教程 (切换到 Visual Basic 教程)

在本教程中,我们将了解为 DataList 控件的EditItemTemplate 添加验证控件,为用户提供一个非常安全的编辑用户界面。

« 前一篇教程  |  下一篇教程 »

简介

迄今为止,在DataList 控件编辑教程中,DataList 控件的编辑界面还没有包含任何前瞻性的用户输入验证,即使是非法的用户输入(例如缺少用户名称或负价格)造成异常。在前一篇教程中,我们学习了如何为 DataList 控件的 UpdateCommand Event Handler添加异常处理代码,从而来捕捉和恰当的显示字段任何与产生的异常有关的信息。比较理想的状况是,在编辑界面中设置验证控件,首先防止用户输入这些非法的数据值。

在本教程中,我们将了解为DataList 控件的EditItemTemplate 添加验证控件,为用户提供一个非常安全的编辑用户界面。具体来说本教程使用了前面教程中创建的几个例子,并为这些例子的编辑界面增加了适当的验证功能。

步骤1 :从处理 BLL 和 DAL 级别的异常 中复制例子

处理 BLL 和 DAL 级别的异常教程中,我们创建了一个页面,该页面使用两列可编辑的 DataList 控件列出了产品的名称和价格。本教程的目的是为DataList 控件的编辑界面增加一些验证控件。具体来说,验证程序将:

  • 要求提供产品的名称
  • 确保输入的价格值是有效的货币格式
  • 确保输入的价格大于或等于0 ,因为负的 UnitPrice 值是非法的。

在为之前的例子增加验证控件之前,我们首先需要从 EditDelete DataList 文件中的 ErrorHandling.aspx 页面里将示例复制到本教程中的 UIValidation.aspx 页面上。要完成该步骤,我们需要将 ErrorHandling.aspx 页面的声明式标记及其源代码都复制过来。执行以下步骤获得声明式标记的第一个拷贝:

  1. 使用 Visual Studio 打开 ErrorHandling.aspx 页面
  2. 找到页面的声明式标记(单击页面底部的Source 按钮)
  3. 复制 <asp:Content> 和 </asp:Content> 标记(第3 行至第32 行)内的文本,如图 1 所示。

图1 :在 <asp:Content> 控件内复制文本

  1. 打开 UIValidation.aspx 页面
  2. 找到该页面的声明式标记
  3. 在 <asp:Content> 控件内粘贴文本

要复制这些源代码,则打开 ErrorHandling.aspx.vb 页面,复制 EditDelete DataList _ErrorHandling 类中的文本。复制这三个 Event handler(Products_EditCommand 、 Products_CancelCommand 和 Products_UpdateCommand )和 DisplayExceptionDetails 方法,但是不要复制类的声明或正在使用的语句。在 UIValidation.aspx.vb 的 EditDelete DataList _UIValidation 类中粘贴所复制的文本。

将内容和代码从 ErrorHandling.aspx 页面复制到 UIValidation.aspx 页面后,花点时间在浏览器中测试一下页面。应该在这两个页面中看到相同的输出,并体验到同样的功能(请参见图 2 )。

图2 :UIValidation.aspx 仿效 ErrorHandling.aspx 页面中的功能

步骤2 :为 DataList 控件的EditItemTemplate 添加验证控件

创建数据条目表格时,用户必须输入各个必须的字段并且用户所提供的输入必须是合法的、格式恰当的值,这一点非常重要。为了帮助用户确保输入的值是合法的,ASP.NET 提供了五个内置的验证控件,这五个控件可以用来验证单个 Web 输入控件的值:

关于这五个控件的更多信息,请参考为编辑与插入界面添加验证控件 教程或查看ASP.NET快速入门教程验证控件部分

对于本教程,我们需要使用 RequiredFieldValidator 控件确保提供了产品的名称,还需要 CompareValidator 控件确保输入的价格是一个大于或等于0 的、合法货币格式的数值。

注意:ASP.NET 1.x 也拥有这个五个控件,而 ASP.NET 2.0 则对这五个控件添加了许多改进。 ASP.NET 1.x 和 ASP.NET 2.0 除了支持 IE 浏览器外,还支持基于客户端的脚本,并且还支持将页面上的验证控件划分成验证组合。有关 2.0 版中新增验证控件特性的更多信息,请参考剖析 ASP.NET 2.0 的验证控件

开始我们先为DataList 控件的EditItemTemplate 添加一个必要的验证控件。您可以在设计器中单击 DataList 控件智能标记上的编辑模板连接或通过声明式语法来完成验证控件的添加。我们使用设计视图中的编辑模板来一步一步的完成这个过程。选择编辑 DataList 控件的 EditItemTemplate 后,使用拖拽的方法从工具箱中拖拽一个 RequiredFieldValidator 验证控件添加到模板编辑界面中,将它放在 ProductName 文本框的后面。 .

图3:在 EditItemTemplate 的 ProductName 文本框后面添加一个RequiredFieldValidator 验证控件

所有验证控件的作用是验证单个 ASP.NET Web 控件的输入。所以,我们应该指示说明刚刚添加的 RequiredFieldValidator 控件是用来验证 ProductName 文本框的;要完成这一步需要将验证控件的ControlToValidate 属性 设置为相应 Web 控件的 ID (在本实例中, ID 号是 ProductName )。接下来将ErrorMessage 属性 设置为“您必须提供产品的名称”并将文本属性 设置为“ * ”。如果给出文本属性值,验证失败时将由验证控件显示该文本。前面要求的ErrorMessage 属性值由 ValidationSummary 控件使用;如果忽略文本属性值,那么当输入非法数据时会显示 ErrorMessage 的属性值。

设置 RequiredFieldValidator 的这三个属性后,屏幕显示类似图 4 。

图4:设置 RequiredFieldValidator 的 ControlToValidate 、ErrorMessage 和文本属性

将 RequiredFieldValidator 添加到 EditItemTemplate 后,接下来就需要为产品的价格文本框添加必要的验证。因为 UnitPrice 是可选的,所以编辑记录时我们无需添加 RequiredFieldValidator 验证控件。不过,我们确实需要添加一个 CompareValidator ,确保将 UnitPrice (如果有)的格式正确赋值为货币并且值大于或等于 0 。

将 CompareValidator 添加到 EditItemTemplate 并将其 ControlToValidate 属性设置为 UnitPrice ,将其 ErrorMessage 属性设置为“价格必须大于或等于0 , 并且不能包含货币符号”,将其文本属性设置为 “*” 。要指示说明UnitPrice 的值必须大于或等于0 ,需要将 CompareValidator 验证控件的Opera tor属性设置为 GreaterThanEqual ,ValueToCompare属性 赋值为0 ,Type 属性 设置为货币。

添加这两个验证控件后,DataList 控件的 EditItemTemplate 的声明式语法应该类似以下语句:

<EditItemTemplate>
    Product name:
        <asp:TextBox ID="ProductName" runat="server"
            Text='<%# Eval("ProductName") %>'></asp:TextBox>
        <asp:RequiredFieldValidator ID="RequiredFieldValidator1"
            ControlToValidate="ProductName"
            ErrorMessage="You must provide the product's name"
            runat="server">*</asp:RequiredFieldValidator>
    <br />
    Price:
        <asp:TextBox ID="UnitPrice" runat="server"
            Text='<%# Eval("UnitPrice", "{0:C}") %>'></asp:TextBox>
        <asp:CompareValidator ID="CompareValidator1"
            ControlToValidate="UnitPrice"
            ErrorMessage="The price must be greater than or equal to zero
                          and cannot include the currency symbol"
            Operator="GreaterThanEqual" Type="Currency" ValueToCompare="0"
            runat="server">*</asp:CompareValidator><br />
    <br />
    <asp:Button ID="UpdateProduct" runat="server" CommandName="Update"
        Text="Update" /> 
    <asp:Button ID="CancelUpdate" runat="server" CommandName="Cancel"
        Text="Cancel" />
</EditItemTemplate>

做完这些更改后,在浏览器中打开页面。如果编辑产品时试图忽略名称或者输入无效的价格,文本框旁边将显示一个星号。如同图 5 所示,包含货币符号的价格值(例如 $19.95 )是非法的。CompareValidator 的 Currency 类型允许使用数字分隔符(例如逗号或句号,究竟使用哪一中这取决于文化设置)和加号或减号,但是不允许货币符号。当正在编辑的界面呈现货币格式的 UnitPrice 时,这种行为可能使用户疑惑。

图5:在输入为非法的文本框旁边出现了一个星号

尽管验证仍然起作用,但是用户编辑记录时必须手工删除货币符号,这让人无法接受。此外,如果在编辑界面中存在非法输入,那么 Update 和 Cancel 按钮被单击时都不会发出数据回发操作。比较理想的状况是 Cancel 按钮会重新返回到 DataList 的预编辑状态而不管用户的输入是否合法。另外在 DataList 控件的 UpdateCommand Event handler中更新产品信息之前,我们还需要确保页面中的数据是有效的,因为可能用户的浏览器不支持 JavaScript 或禁用了 JavaScript 支持,导致忽略验证控件的客户端程序。

从 EditItemTemplate 的 UnitPrice 文本框中移除货币符号

使用 CompareValidator 验证控件的 Currency Type 时,被验证的输入必须不能包含任何货币符号。这些符号的存在会使 CompareValidator 将该输入标记为非法输入。但是编辑界面通常在 UnitPrice 文本框中包含货币符号,这意味着用户在保存所做的更改时必须将货币符号移除。我们有三种方法来改正这一点:

  1. 配置 EditItemTemplate ,这样 UnitPrice 文本框就不会被格式化成货币格式。
  2. 将 CompareValidator 验证控件替换成一个 RegularExpressionValidator 控件,使用该控件来检查被正确格式化的货币值,从而允许用户输入货币符号。难题是这里用来验证货币值的正则表达式不如 CompareValidator 验证控件那么直接,而且如果考虑到文化差异设置还需要编写代码 。
  3. 完全移除验证控件,依靠 GridView 控件的RowUpdating Event handler 中的服务器端程序来实现。

让我们先来尝试一下第一种方法。通常UnitPrice 被格式化成一个货币值,这是因为 EditItemTemplate 中文本框的数据绑定表达式是:<%# Eval("UnitPrice", "{0:c}") %> 。将 Eval 语句改为 Eval("UnitPrice", "{0:n2}") ,这个语句会将结果格式化成两位精度的数字。可以直接通过声明式语法或单击 DataList 控件的 EditItemTemplate 中 UnitPrice 文本框的 Edit DataBindings 链接来更改 Eval 语句。

更改后,正在编辑界面中的格式化价格包含有逗号作为组分隔符,句号作为小数点分隔符,但停止使用货币符号。

注意:虽然将货币格式移出了编辑界面,但是我发现把货币符号作为文本放在文本框的外面是非常有益的。这可以暗示用户无须再输入货币符号。

固定 Cancel 按钮

默认情况下,Web 验证控件在客户端使用 JavaScript 执行验证。当单击一个按钮、链接按钮和位图按钮时,页面上的验证控件会在数据回发操作产生之前在客户端进行验证,如果存在非法数据,那么数据回发操作就会被取消。对于某些按钮来说,有些数据验证可能是无关紧要的,如果这时由于这些无关紧要的非法数据而取消这些按钮的数据回发操作,这无疑是非常令人讨厌的事情。

Cancel 按钮就是一个这样的例子。想像一下用户输入了非法数据(例如他忽略了产品的名称),假设用户根本不想保存这个产品,因此单击了 Cancel 按钮。现在,Cancel 按钮触发了页面上的验证控件,而验证控件报告缺少产品名称因而阻止了回传操作。那么,我们的用户就不得不在 ProductName 文本框中输入某些文字才能取消整个编辑过程。

非常值得庆幸的是,按钮、链接按钮和位图按钮都有一个CausesValidation属性,该属性可用来指示单击按钮时是否需要验证逻辑(该属性值默认为 True ) 。请将 Cancel 按钮的 CausesValidation 属性值设置为 False 。

确保 UpdateCommand Event handler 中的输入有效

由于验证控件会忽略客户端脚本,所以当用户输入非法输入时验证控件会取消所有由按钮、链接按钮或位图按钮发起的数据回发操作,因为这些控件的默认CausesValidation 属性值为 True 。所以,如果用户使用一个过时的浏览器或他的浏览器禁用了 JavaScript 支持,那么就不会执行客户端的验证检查。

一旦产生数据回发操作,所有的 ASP.NET 验证控件会立刻重复执行它们的验证逻辑并通过Page.IsValid属性 报告所有页面输入的有效性。虽然页面循环没有因为任何基于 Page.IsValid 值的方法而中断或终止,但是作为一名开发人员,我们有责任在继续执行那些假定为有效输入数据的代码之前,确保 Page.IsValid 的属性值为 True 。

如果某用户禁用了 JavaScript ,然后 访问页面并编辑产品,输入了一个值为 “ 太昂贵 ” 的价格并单击了 Update 按钮,那么将忽略客户端的验证,接着会产生数据回发操作。产生数据回发操作后,将执行 ASP.NET 页面的 UpdateCommand Event Handler并在试图将“太昂贵”转换成十进制时产生异常。因为我们拥有异常处理机制,所以会正确处理这个异常。但是如果 Page.IsValid 的值为 True ,就只能先继续执行 UpdateCommand Event Handler来阻止数据的传入。

直接在Try 模块之前添加下列代码来启动 UpdateCommand Event handler :

if (!Page.IsValid)
    return;

添加之后,只要提交的数据是合法的,就会尝试更新产品。由于验证控件的客户端脚本的原因,大多数用户不能回发非法数据,但是浏览器不支持 JavaScript 的用户或禁用了 JavaScript 的用户可以忽略客户端的验证并提交非法的数据。

注意:一些敏锐的用户会想起在使用 GridView 控件更新数据时,我们并没有在页面的代码文件类中明确地检查 Page.IsValid 属性。这是因为 GridView 会为我们查询 Page.IsValid 的属性值,只要它返回值为 True ,GridView 就会继续进行更新。

步骤3 :汇总数据输入问题

除了五个验证控件,ASP.NET 还包含ValidationSummary 控件,该控件显示检测到无效数据的验证控件的错误消息。该汇总数据可以在网页上以文本方式显示,也可以通过模式客户端消息框显示。我们可以在本教程中加入一个能够汇总所有验证问题的消息框。

要实现该目标,请从工具箱拖拉一个 ValidationSummary  控件到设计器。ValidationSummary 控件的位置并不重要,因为我们配置它后,只让它作为一个消息框来显示汇总信息。添加完该控件后,将其ShowSummary 属性 设置为 False ,将ShowMessageBox 属性设置为 True 。完成这些添加之后,所有的验证错误都被汇总在客户端的消息框中(请参见图 6 )。

图6 :验证错误被汇总在客户端的消息框中

小结

在本教程中,我们了解了怎样使用验证控件减少一些可能会发生的异常,并且在更新工作流中试图使用用户的输入之前提前确保用户输入的有效性。 ASP.NET 提供了五个 Web 控件,这五个控件专门设计用于检查 Web 控件的输入并报告输入的合法性。在本篇教程中,我们使用了五个控件中的两个( RequiredFieldValidator 控件和 CompareValidator 控件)来确保提供了产品的名称和价格为货币格式并且数值大于或等于 0 。

向DataList 控件的编辑界面添加验证控件非常简单,您只需要将它们从工具箱中拖拉到 EditItemTemplate 中,然后设置少量属性即可。默认情况下,验证控件会自动使用客户端验证脚本,它们在产生数据回发操作时的服务器端验证,累计存储在 Page.IsValid 属性中。要在单击按钮、链接按钮或位图按钮时忽略客户端验证,请将按钮的 CausesValidation 属性值设置为 False 。另外当产生数据回发时,则在使用提交的数据执行任何任务前务必确保 Page.IsValid 属性返回值为 True 。

到目前为止,我们所尝试的所有 DataList 控件的编辑教程都有非常简单的编辑界面 — 一个文本框用于输入产品名称,另一文本框用于输入产品价格。但是编辑界面能够包含各种不同的 Web 控件,例如 DropDownLists 、 Calendars 、 RadioButtons 、 CheckBoxes 等等。在接下来的教程中我们将着眼于使用各种各样的 Web 控件来构建界面。

快乐编程!

 

 

下一篇教程