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

简介

DataList 的 EditItemTemplate 对其可编辑界面进行了定义。迄今为止我们所详细探讨的所有DataList 可编辑实例中,可编辑界面都是由 Web 文本框控件组成。在 前一篇教程中,通过添加验证控件,我们提高了编辑时间用户的经验。

EditItemTemplate 可以进一步扩展,包含除文本框之外的其他 Web 控件,例如 DropDownList 、RadioButtonList 、Calendar 等。与使用 TextBoxes 的情况相同,在定制编辑界面以包含其他 Web 控件时,可以运用如下步骤:

  1. 将 Web 控件添加至 EditItemTemplate 。
  2. 使用数据绑定语法将相应的数据字段值分配至合适的属性中。
  3. 在 UpdateCommand Event Handler 中,通过编程访问 Web 控件值,并将其传递给合适的 BLL 方法。

在本教程中,我们将为 Datalist 创建一个更加丰富的编辑界面,界面中包含 DropDownList 和 CheckBox 。具体来说,我们将创建的 DataList 中可以列出产品信息并且允许对产品名称、供应商、类别以及断货状态进行更新(见图 1 )。

图1 :编辑界面包括一个文本框、两个 DropDownList 和一个 CheckBox

步骤1 :显示产品信息

在我们创建 DataList 的可编辑界面前,需要先构建只读界面。首先,从 EditDeleteDataList 文件夹中打开 CustomizedUI.aspx 页面,并且从设计器中将 DataList 添加至该页面,将其 ID 属性设置为“产品” 。在 DataList 的智能标记中创建一个新的 ObjectDataSource 。为这一新的 ObjectDataSource ProductsDataSource 命名,并且将其设置为可以从 ProductsBLL 类中的 GetProducts 方法中检索数据。和前面的可编辑 DataList 教程中的情况相同,我们将通过直接进入业务逻辑层的方式,对已编辑产品信息进行更新。相应的,将 UPDATE 、 INSERT 、 DELETE 选项卡中的下拉列表设置成 (None) 。

图2 :将 UPDATE 、INSERT 、DELETE 选项卡的下拉列表设置为 (None)

配置 ObjectDataSource 后,对于列出每个返回数据字段名称和数值的DataList ,Visual Studio 将为其创建一个默认ItemTemplate 。对 ItemTemplate 进行修改,以便该模板在 <h4> 元素中列出产品名称,同时列出类别名称、供应商名称、价格以及断货状态。除此之外,添加一个 Edit 按钮,确保其 CommandName 属性设置为“Edit”。ItemTemplate 的声明式标记如下:

<ItemTemplate> 
    <h4> 
        <asp:Label ID="ProductNameLabel" runat="server" 
            Text='<%# Eval("ProductName") %>' /> 
    </h4> 
    <table border="0"> 
        <tr> 
            <td class="ProductPropertyLabel">Category:</td> 
            <td class="ProductPropertyValue"> 
                <asp:Label ID="CategoryNameLabel" runat="server" 
                    Text='<%# Eval("CategoryName") %>' /> 
            </td> 
            <td class="ProductPropertyLabel">Supplier:</td> 
            <td class="ProductPropertyValue"> 
                <asp:Label ID="SupplierNameLabel" runat="server" 
                    Text='<%# Eval("SupplierName") %>' /> 
            </td> 
        </tr> 
        <tr> 
            <td class="ProductPropertyLabel">Discontinued:</td> 
            <td class="ProductPropertyValue"> 
                <asp:Label ID="DiscontinuedLabel" runat="server" 
                    Text='<%# Eval("Discontinued") %>' /> 
            </td> 
            <td class="ProductPropertyLabel">Price:</td> 
            <td class="ProductPropertyValue"> 
                <asp:Label ID="UnitPriceLabel" runat="server" 
                    Text='<%# Eval("UnitPrice", "{0:C}") %>' /> 
            </td> 
        </tr> 
        <tr> 
            <td colspan="4"> 
                <asp:Button runat="Server" ID="EditButton" 
                    Text="Edit" CommandName="Edit" /> 
            </td> 
        </tr> 
    </table> 
    <br /> 
</ItemTemplate>

以上的标记使用一个<h4> 标题,为产品名称列出了产品信息,并且为其余的字段安排了一个四栏 <table> 。在 Styles.css 中进行定义的 ProductPropertyLabel 以及 ProductPropertyValue CSS 类已经在前面的教程中讨论过。图 3 显示了通过浏览器浏览时的进度。

图3 :显示每个产品的名称、供应商、类别、断货状态和价格

步骤2 :在编辑界面中添加 Web 控件

构建定制的 DataList 编辑界面的第一步是在 EditItemTemplate 中添加所需的 Web 控件。具体来说,我们需要一个 DropDownList 显示类别,一个 DropDownList 显示供应商,一个 CheckBox 用于 断货状态。因为在本实例中产品价格是不可编辑的,所以我们可以使用一个 Web 标签控件,继续显示产品价格。

要定制编辑界面,则在 DataList 中的智能标记中单击“Edit Templates”链接,并从下拉列表中选择 EditItemTemplate 选项。在 EditItemTemplate 中添加一个 DropDownList ,并且将其 ID 设置为 Categories。

图4 :添加 DropDownList 用于分类

接下来,在 DropDownList 的智能标记中,选择 “Choose Data Source” 选项,创建一个新的名为 CategoriesDataSource 的 ObjectDataSource 。将该 ObjectDataSource 设置为使用 CategoriesBLL 类的 GetCategories() 方法(见图 5 )。接下来,DropDownList 的 数据源设置向导会提示为每个 ListItem 的 Text 和 Value 属性使用数据字段。使DropDownList 显示CategoryName 数据字段,并且使用 Category ID 作为值,如图 6 所示。

图5 :创建一个新的名为 CategoriesDataSource 的 ObjectDataSource

图6 :配置 DropDownList 的 Display 与 Value 字段

重复该系列步骤,为供应商创建一个DropDownList 。将该 DropDownList 的 ID 设置为 Suppliers ,并将其 ObjectDataSource 命名为 SuppliersDataSource 。

在添加这两个 DropDownList 后,为断货状态添加一个 CheckBox ,并且为产品名称添加一个文本框。分别将CheckBox 和文本框的 ID 设置为 Discontinued 和 ProductName。添加 RequiredFieldValidator 确保用户为产品名称赋值。

最后,添加 Update 和 Cancel 按钮。请牢记,对于这两个按钮来说,他们的 CommandName 属性必须分别设为 “Update” 和 “ Cancel ” 。

随意设计编辑界面的布局。我曾经从只读界面中选择使用相同的四栏<table> 布局,如以下的声明式语句以及屏幕截图所示 :

<EditItemTemplate> 
    <h4> 
        <asp:Label ID="ProductNameLabel" runat="server" 
            Text='<%# Eval("ProductName") %>' /> 
    </h4> 
    <table border="0"> 
        <tr> 
            <td class="ProductPropertyLabel">Name:</td> 
            <td colspan="3" class="ProductPropertyValue"> 
                <asp:TextBox runat="server" ID="ProductName" Width="90%" /> 
                <asp:RequiredFieldValidator ID="RequiredFieldValidator1" 
                    ControlToValidate="ProductName" 
                    ErrorMessage="You must enter a name for the product." 
                    runat="server">*</asp:RequiredFieldValidator> 
            </td> 
        </tr> 
        <tr> 
            <td class="ProductPropertyLabel">Category:</td> 
            <td class="ProductPropertyValue"> 
                <asp:DropDownList ID="Categories" runat="server" 
                    DataSourceID="CategoriesDataSource" 
                    DataTextField="CategoryName" DataValueField="CategoryID" /> 
            </td> 
            <td class="ProductPropertyLabel">Supplier:</td> 
            <td class="ProductPropertyValue"> 
                <asp:DropDownList ID="Suppliers" DataTextField="CompanyName" 
                    DataSourceID="SuppliersDataSource" 
                    DataValueField="SupplierID" runat="server" /> 
            </td> 
        </tr> 
        <tr> 
            <td class="ProductPropertyLabel">Discontinued:</td> 
            <td class="ProductPropertyValue"> 
                <asp:CheckBox runat="server" id="Discontinued" /> 
            </td> 
            <td class="ProductPropertyLabel">Price:</td> 
            <td class="ProductPropertyValue"> 
                <asp:Label ID="UnitPriceLabel" runat="server" 
                    Text='<%# Eval("UnitPrice", "{0:C}") %>' /> 
            </td> 
        </tr> 
        <tr> 
            <td colspan="4"> 
                <asp:Button runat="Server" ID="UpdateButton" CommandName="Update" 
                    Text="Update" /> 
                    
                <asp:Button runat="Server" ID="CancelButton" CommandName="Cancel" 
                    Text="Cancel" CausesValidation="False" /> 
            </td> 
        </tr> 
    </table> 
    <br /> 
 
    <asp:ObjectDataSource ID="CategoriesDataSource" runat="server" 
        OldValuesParameterFormatString="original_{0}" SelectMethod="GetCategories" 
        TypeName="CategoriesBLL"> 
    </asp:ObjectDataSource> 
 
    <asp:ObjectDataSource ID="SuppliersDataSource" runat="server" 
        OldValuesParameterFormatString="original_{0}" SelectMethod="GetSuppliers" 
        TypeName="SuppliersBLL"> 
    </asp:ObjectDataSource> 
</EditItemTemplate>

图7 :编辑界面的布局类似只读界面

步骤3:创建 EditCommand 和CancelCommand Event Handler

目前,在 EditItemTemplate 中没有数据绑定语法(UnitPriceLabel 除外,它从 ItemTemplate 中逐字进行复制)。我们会马上添加数据绑定数据,但是首先让我们为 DataList 的 EditCommand 和 CancelCommand 事件创建 Event Handler。请回忆一下,EditCommand Event Handler的责任是为被单击了 Edit 按钮的 DataList 项目呈现编辑界面,而 CancelCommand 的工作是将 DataList 返回至编辑前的状态。

创建这两个Event Handler ,使两个处理器使用如下代码:

protected void Products_EditCommand(object source, DataListCommandEventArgs e) 

    // Set the DataList's EditItemIndex property and rebind the data 
    Products.EditItemIndex = e.Item.ItemIndex; 
    Products.DataBind(); 

 
protected void Products_CancelCommand(object source, DataListCommandEventArgs e) 

    // Return to DataList to its pre-editing state 
    Products.EditItemIndex = -1; 
    Products.DataBind(); 
}

当这两个 Event Handler 创建完成后,单击 Edit 按钮显示编辑界面,而单击 Cancel 按钮,将已编辑项目返回至其只读模式下。图 8 显示了在为 Chef Anton’s Gumbo Mix 单击编辑按钮后,DataList 的情况。因为我们并没有在编辑界面中添加任何数据绑定语法,所以ProductName 文本框为空,断货 CheckBox 为未选中状态,并且从分类和供应商 DropDownList 中选择的第一批项目也未被选中。

图8:单击 Edit 按钮显示编辑界面

步骤4 :在编辑界面添加数据绑定语法

为了使编辑界面显示目前的产品值,我们需要使用数据绑定语法将数据字段值分配至适当的Web 控件值中。通过进入编辑模板屏幕,并从 Web 控件的智能标记中选择“Edit DataBindings”链接,数据绑定语法就可以通过设计器进行应用。或者,数据绑定语法可以直接添加到声明式标记中。

将 ProductName 文本框的文本属性赋值为 ProductName 数据字段值,为分类与供应商 DropDownList 的 SelectedValue 属性赋值 CategoryID 和 SupplierID 数据字段值,为断货 CheckBox 的 Checked 属性赋值 Discontinued 数据字段值 。在完成这些改变后,通过设计器或者直接通过声明式标记,再次通过浏览器访问页面,单击 Chef Anton’s Gumbo Mix 的 Edit 按钮。如图 9 所示,数据绑定语法已经将目前的值添加到了文本框、DropDownList 和 CheckBox 中。

图9 :单击 Edit 按钮显示编辑界面

步骤5 :在UpdateCommand Event Handler 中保存用户所做的改变

当用户在编辑一种产品,并单击Update 按钮时,将发生回传,并且激发 DataList 的 UpdateCommand 事件。在 Event Handler 中,我们需要从 EditItemTemplate 中的 Web 控件读取值,并与 BLL 合作更新数据库中的产品。正如我们在前面的教程中所看到的那样,已更新产品的 Product ID 可以通过 DataKeys 集合进行访问。用户所输入的字段可以使用 FindControl("controlID") 通过编程引用 Web 控件的方式进行访问,如以下代码所示:

protected void Products_UpdateCommand(object source, DataListCommandEventArgs e) 

    // Make sure the page is valid... 
    if (!Page.IsValid) 
        return; 
 
    // Read in the ProductID from the DataKeys collection 
    int productID = Convert.ToInt32(Products.DataKeys[e.Item.ItemIndex]); 
 
    // Read in the product name and price values 
    TextBox productName = (TextBox)e.Item.FindControl("ProductName"); 
    DropDownList categories = (DropDownList)e.Item.FindControl("Categories"); 
    DropDownList suppliers = (DropDownList)e.Item.FindControl("Suppliers"); 
    CheckBox discontinued = (CheckBox)e.Item.FindControl("Discontinued"); 
 
    string productNameValue = null; 
    if (productName.Text.Trim().Length > 0) 
        productNameValue = productName.Text.Trim(); 
 
    int categoryIDValue = Convert.ToInt32(categories.SelectedValue); 
 
    int supplierIDValue = Convert.ToInt32(suppliers.SelectedValue); 
 
    bool discontinuedValue = discontinued.Checked; 
 
 
    // Call the ProductsBLL's UpdateProduct method... 
    ProductsBLL productsAPI = new ProductsBLL(); 
    productsAPI.UpdateProduct(productNameValue, categoryIDValue, supplierIDValue, 
                              discontinuedValue, productID); 
 
    // Revert the DataList back to its pre-editing state 
    Products.EditItemIndex = -1; 
    Products.DataBind(); 
}

代码先查阅 Page.IsValid 属性,确保页面中所有的验证控件有效。如果Page.IsValid 是 True ,将从 DataKeys 集合读取已编辑产品的 ProductID 值,并通过编程引用 EditItemTemplate 中的数据输入 Web 控件。接下来,将来自这些 Web 控件的数值读取到变量中,随后传递至合适的 UpdateProduct 过载中。在完成数据更新后,DataList 就会返回至编辑前的状态。

注意:我忽略了教程 处理 BLL和 DAL级别的异常中添加的异常处理程序,这样做的目的是为了将注意力放在代码和本实例上。作为练习,在完成本教程后将添加这一功能。

步骤6 : 处理 NULL CategoryID 和SupplierID 值

Northwind 数据库允许将产品表的 CategoryID 和 SupplierID 列使用 NULL 值 。然而 , 我们的编辑界面目前并不兼容 “NULL ” 值。如果我们试图编辑CategoryID 或 SupplierID 值为 NULL 的产品,我们会获得一个有类似如下错误信息的 ArgumentOutOfRangeException 异常: “'Categories' has a SelectedValue which is invalid because it does not exist in the list of items.” 同时,目前没有方法将产品的分类或供应商值从非NULL 值改变为 NULL 值。

要支持使用 NULL 值的 分类和供应商 DropDownList ,我们需要添加一个额外的 ListItem 。我通常选择使用“(None)”作为这一 ListItem 的文本值,但是您可以随意对其进行改变(比如将其改变为空字符串)。最后,请牢记将DropDownList 的 AppendDataBoundItems 设置为“True”,如果忘记这个设置,那么与DropDownList 相互绑定的分类以及供应商数值将会覆盖静态添加的 ListItem。

在完成这些改变后,DataList 的 EditItemTemplate 中的 DropDownList 标记应该类似如下标记:

<asp:DropDownList ID="Categories" DataSourceID="CategoriesDataSource" 
    DataTextField="CategoryName" DataValueField="CategoryID" runat="server" 
    SelectedValue='<%# Eval("CategoryID") %>' AppendDataBoundItems="True"> 
    <asp:ListItem Value=" Selected="True">(None)</asp:ListItem> 
</asp:DropDownList> 
 
... 
 
<asp:DropDownList ID="Suppliers" DataSourceID="SuppliersDataSource" 
    DataTextField="CompanyName" DataValueField="SupplierID" runat="server" 
    SelectedValue='<%# Eval("SupplierID") %>' AppendDataBoundItems="True"> 
    <asp:ListItem Value=" Selected="True">(None)</asp:ListItem> 
</asp:DropDownList>

注意:可以通过设计器或直接通过声明式语句将静态ListItem 添加至 DropDownList 中。当添加 DropDownList 项表示数据库 NULL 值时,请确保通过声明式语句添加 ListItem 。如果在设计器中使用 ListItem Collection Editor,在赋值空字符串时,生成的声明式语句将会完全忽略 Value 设置,创建的声明式标记类似于:<asp:ListItem>(None)</asp:ListItem>.尽管看起来没有什么问题,丢失了 Value 值将使得 DropDownList 使用 Text 属性顶替 Value。这就意味着,如果该 NULL ListItem 被选中,将尝试为产品数据字段赋值 "( none)" (在本教程中指的是 Category ID 或 Supplier ID ),这就会导致发生异常。通过明确地设置 Value="" ,当 NULL ListItem 被选中时,将为产品数据字段赋值 NULL 值。

花点时间在浏览器中查看一下进度。当对一种产品进行编辑时,注意,分类和供应商的DropDownList 在 DropDownList 的一开始都会有一个 "( None )" 选项。

图10:分类和供应商 DropDownList 中都包含一个 "(None)" 选项

为了将"(None)" 选项作为数据库NULL 值进行保存,我们需要回到 UpdateCommand Event Handler 中。将 categoryIDValue 和 supplierIDValue 变量改为可为零整数,并且只有在 DropDownList 的SelectedValue 不为空白字符串的情况下,为这两个变量赋值"Nothing" 以外的值

int? categoryIDValue = null; 
if (!string.IsNullOrEmpty(categories.SelectedValue)) 
    categoryIDValue = Convert.ToInt32(categories.SelectedValue); 
 
int? supplierIDValue = null; 
if (!string.IsNullOrEmpty(suppliers.SelectedValue)) 
    supplierIDValue = Convert.ToInt32(suppliers.SelectedValue);

在完成该改变后,如果用户从任何一个下拉列表中选择了"(None)" 选项,将为UpdateProduct BLL 方法传递一个 与 NULL 数据库值相对应的 “Nothing” 值。

小结

在本教程中,我们了解了如何创建一个更复杂的 Datalist 编辑界面,在编辑界面中包含三种不同的 Web 输入控件:一个文本框、两个 DropDownList 和一个 CheckBox ,以及验证控件。构建编辑界面时,不管使用了何种 Web 控件,其步骤相同:首先将 Web 控件添加至 DataList 的 EditItemTemplate中;使用数据绑定语法用适当 Web 控件属性为相应数据字段赋值;在UpdateCommand Event Handler 中,通过编程访问 Web 控件及其相应的属性,将其值传递给 BLL 。

创建编辑界面时,不管其是由文本框组成还是由不同 Web 控件组成,一定要正确处理数据库 NULL 值。在处理 NULL 问题时,不仅需要在编辑界面中正确显示现有的 NULL 值,还需要为如何将一个数值转变为 NULL 值提供方法。对于 DataList 中的 DropDownList 来说,这通常意味着需要添加一个 Value 属性明确设置为空白字符串 ( Value="") 的静态 ListItem ,并将一些代码添加至 UpdateCommand Event Handler中以确定是否选中了 NULL ListItem 。

快乐编程!

posted @ 2016-05-01 23:23  迅捷之风  阅读(176)  评论(0编辑  收藏  举报