自定义 DataList 的编辑界面 (VB)

作者 :Scott Mitchell

下载 PDF

在本教程中,我们将为 DataList 创建更丰富的编辑界面,其中包括 DropDownLists 和 CheckBox。

简介

DataList 中的 EditItemTemplate 标记和 Web 控件定义其可编辑接口。 在我们到目前为止检查的所有可编辑 DataList 示例中,可编辑的界面都由 TextBox Web 控件组成。 在 前面的教程中 ,我们通过添加验证控件改进了编辑时用户体验。

EditItemTemplate可以进一步扩展,以包含除 TextBox 以外的 Web 控件,例如 DropDownLists、RadioButtonLists、Calendars 等。 与 TextBoxs 一样,在自定义编辑界面以包含其他 Web 控件时,请使用以下步骤:

  1. 将 Web 控件添加到 EditItemTemplate
  2. 使用数据绑定语法将相应的数据字段值分配给相应的属性。
  3. 在事件处理程序中 UpdateCommand ,以编程方式访问 Web 控件值,并将其传递到相应的 BLL 方法中。

在本教程中,我们将为 DataList 创建更丰富的编辑界面,其中包括 DropDownLists 和 CheckBox。 具体而言,我们将创建一个 DataList,用于列出产品信息,并允许更新产品名称、供应商、类别和停产状态, (请参阅图 1) 。

编辑界面包括一个 TextBox、两个 DropDownList 和一个 CheckBox

图 1:编辑界面包括一个 TextBox、两个 DropDownList 和一个 CheckBox (单击以查看全尺寸图像)

步骤 1:显示产品信息

在创建 DataList 的可编辑接口之前,首先需要生成只读接口。 首先从 文件夹中打开CustomizedUI.aspx页面,然后从 Designer向页面添加 DataList,并将其ID属性设置为 ProductsEditDeleteDataList 在 DataList 的智能标记中,创建新的 ObjectDataSource。 将此新的 ObjectDataSource ProductsDataSource 命名为 ,并将其配置为从 ProductsBLL 类 s GetProducts 方法检索数据。 与前面的可编辑 DataList 教程一样,我们将通过直接转到业务逻辑层来更新已编辑的产品信息。 相应地,将“更新”、“插入”和“删除”选项卡中的下拉列表设置为“无”) (。

将“更新”、“插入”和“删除”选项卡 Drop-Down Lists 设置为“无” ()

图 2:将“更新”、“插入”和“删除”选项卡 Drop-Down Lists 设置为“无 () (单击以查看全尺寸图像)

配置 ObjectDataSource 后,Visual Studio 将为 DataList 创建一个默认值 ItemTemplate ,其中列出了返回的每个数据字段的名称和值。 修改 , ItemTemplate 以便模板列出元素中的 <h4> 产品名称以及类别名称、供应商名称、价格和停产状态。 此外,添加“编辑”按钮,确保其 CommandName 属性设置为“编辑”。 我的 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> 来布局产品信息。 ProductPropertyLabel在 中Styles.css定义的 和 ProductPropertyValue CSS 类已在前面的教程中进行了讨论。 图 3 显示了通过浏览器查看时的进度。

将显示每个产品的名称、供应商、类别、停产状态和价格

图 3:显示每个产品的名称、供应商、类别、停产状态和价格 (单击以查看全尺寸图像)

步骤 2:将 Web 控件添加到编辑界面

生成自定义 DataList 编辑界面的第一步是将所需的 Web 控件添加到 EditItemTemplate。 具体而言,我们需要一个 DropDownList 作为类别,另一个用于供应商,一个 CheckBox 用于停产状态。 由于在此示例中,产品价格不可编辑,因此我们可以使用标签 Web 控件继续显示它。

若要自定义编辑界面,请单击 DataList 智能标记中的“编辑模板”链接, EditItemTemplate 然后从下拉列表中选择选项。 将 DropDownList 添加到 ,EditItemTemplate并将其IDCategories设置为 。

为类别添加 DropDownList

图 4:为“类别”添加 DropDownList (单击以查看全尺寸图像)

接下来,从 DropDownList 的智能标记中选择“选择数据源”选项,并创建名为 CategoriesDataSource的新 ObjectDataSource。 配置此 ObjectDataSource 以使用 CategoriesBLL 类方法 GetCategories() (请参阅图 5) 。 接下来,DropDownList 的数据源配置向导会提示输入要用于每个 ListItem s 和Value属性的数据Text字段。 让 DropDownList 显示 CategoryName 数据字段并使用 CategoryID 作为值,如图 6 所示。

创建新的对象DataSource 命名类别DataSource

图 5:新建名为 CategoriesDataSource 的对象数据源 (单击以查看全尺寸图像)

配置 DropDownList 的显示字段和值字段

图 6:配置 DropDownList 的显示字段和值字段 (单击以查看全尺寸图像)

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

添加两个 DropDownList 后,为停产状态添加 CheckBox,为产品名称添加 TextBox。 ID分别将 CheckBox 和 TextBox 的 设置为 DiscontinuedProductName。 添加 RequiredFieldValidator 以确保用户为产品名称提供值。

最后,添加“更新”和“取消”按钮。 请记住,对于这两个按钮,必须分别将其 CommandName 属性设置为“更新”和“取消”。

随意布局编辑界面,但你喜欢。 我已选择从只读界面使用相同的四列 <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"
                    DataSourceID="SuppliersDataSource" DataTextField="CompanyName"
                    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>

编辑界面的布局类似于 Read-Only 接口

图 7:编辑界面的布局类似于 Read-Only 界面 (单击以查看全尺寸图像)

步骤 3:创建 EditCommand 和 CancelCommand 事件处理程序

目前,除了 从 ItemTemplate) UnitPriceLabel逐字复制的 , (中没有数据绑定语法EditItemTemplate。 我们将暂时添加数据绑定语法,但首先让我们为 DataList EditCommandCancelCommand 事件创建事件处理程序。 回想一下,事件处理程序的责任 EditCommand 是呈现单击了“编辑”按钮的 DataList 项的编辑界面,而 CancelCommand s 作业是将 DataList 返回到其预编辑状态。

创建这两个事件处理程序,并让它们使用以下代码:

Protected Sub Products_EditCommand(source As Object, e As DataListCommandEventArgs) _
    Handles Products.EditCommand
    ' Set the DataList's EditItemIndex property to the
    ' index of the DataListItem that was clicked
    Products.EditItemIndex = e.Item.ItemIndex
    ' Rebind the data to the DataList
    Products.DataBind()
End Sub
Protected Sub Products_CancelCommand(source As Object, e As DataListCommandEventArgs) _
    Handles Products.CancelCommand
    ' Set the DataList's EditItemIndex property to -1
    Products.EditItemIndex = -1
    ' Rebind the data to the DataList
    Products.DataBind()
End Sub

完成这两个事件处理程序后,单击“编辑”按钮将显示编辑界面,单击“取消”按钮会将已编辑的项目返回到只读模式。 图 8 显示单击 Chef Anton 的 Gumbo Mix 的“编辑”按钮后的数据列表。 由于我们尚未向编辑界面添加任何数据绑定语法, ProductName TextBox 为空, Discontinued CheckBox 处于未选中状态,并且从 CategoriesSuppliers DropDownLists 中选择的第一个项。

显示添加 EditCommand 和 CancelCommand 事件处理程序后 DataList EditItemTemplate 且已选择“编辑”按钮的屏幕截图。

图 8:单击“编辑”按钮显示编辑界面 (单击以查看全尺寸图像)

步骤 4:向编辑接口添加数据绑定语法

若要使编辑界面显示当前产品的 值,我们需要使用数据绑定语法将数据字段值分配给相应的 Web 控件值。 可以通过Designer应用数据绑定语法,方法是转到“编辑模板”屏幕,然后从 Web 控件智能标记中选择“编辑数据绑定”链接。 或者,可以将数据绑定语法直接添加到声明性标记。

将数据 ProductName 字段值分配给 ProductName TextBox 属性 Text ,将 CategoryIDSupplierID 数据字段值分配给 CategoriesSuppliers DropDownLists SelectedValue 属性,并将 Discontinued 数据字段值分配给 Discontinued CheckBox 的 Checked 属性。 进行这些更改后,无论是通过Designer还是直接通过声明性标记,通过浏览器重新访问页面,然后单击 Chef Anton s Gumbo Mix 的“编辑”按钮。 如图 9 所示,数据绑定语法已将当前值添加到 TextBox、DropDownLists 和 CheckBox 中。

显示添加 DataBinding 语法并选择“编辑”按钮后 DataList EditItemTemplate 的屏幕截图。

图 9:单击“编辑”按钮显示编辑界面 (单击以查看全尺寸图像)

步骤 5:在 UpdateCommand 事件处理程序中保存用户更改

当用户编辑产品并单击“更新”按钮时,会发生回发,并触发 DataList 事件 UpdateCommand 。 在事件处理程序中,我们需要从 和 与 BLL 接口的 EditItemTemplate Web 控件中读取值,以更新数据库中的产品。 正如我们在前面的教程中看到的那样, ProductID 可通过 集合访问 DataKeys 更新产品的 。 通过使用 以编程方式引用 Web 控件 FindControl("controlID")来访问用户输入的字段,如以下代码所示:

Protected Sub Products_UpdateCommand(source As Object, e As DataListCommandEventArgs) _
    Handles Products.UpdateCommand
    If Not Page.IsValid Then
        Exit Sub
    End If
    ' Read in the ProductID from the DataKeys collection
    Dim productID As Integer = Convert.ToInt32(Products.DataKeys(e.Item.ItemIndex))
    ' Read in the product name and price values
    Dim productName As TextBox = CType(e.Item.FindControl("ProductName"), TextBox)
    Dim categories As DropDownList=CType(e.Item.FindControl("Categories"), DropDownList)
    Dim suppliers As DropDownList = CType(e.Item.FindControl("Suppliers"), DropDownList)
    Dim discontinued As CheckBox = CType(e.Item.FindControl("Discontinued"), CheckBox)
    Dim productNameValue As String = Nothing
    If productName.Text.Trim().Length > 0 Then
        productNameValue = productName.Text.Trim()
    End If
    Dim categoryIDValue As Integer = Convert.ToInt32(categories.SelectedValue)
    Dim supplierIDValue As Integer = Convert.ToInt32(suppliers.SelectedValue)
    Dim discontinuedValue As Boolean = discontinued.Checked
    ' Call the ProductsBLL's UpdateProduct method...
    Dim productsAPI As New ProductsBLL()
    productsAPI.UpdateProduct(productNameValue, categoryIDValue, supplierIDValue, _
        discontinuedValue, productID)
    ' Revert the DataList back to its pre-editing state
    Products.EditItemIndex = -1
    Products.DataBind()
End Sub

代码首先会查阅 Page.IsValid 属性,以确保页面上的所有验证控件都有效。 如果 Page.IsValidTrue,则从DataKeys集合中读取已编辑的产品ProductID值,并且以编程方式引用 中的数据EditItemTemplate条目 Web 控件。 接下来,将这些 Web 控件中的值读取到变量中,然后传递到相应的 UpdateProduct 重载。 更新数据后,DataList 将返回到其预编辑状态。

注意

为了保持代码和此示例的焦点,我省略了 在处理 BLL 和 DAL-Level 异常 教程中添加的异常处理逻辑。 作为练习,请在完成本教程后添加此功能。

步骤 6:处理 NULL CategoryID 和 SupplierID 值

Northwind 数据库允许NULL表和CategoryIDSupplierID列的值Products。 但是,我们的编辑界面当前无法容纳 NULL 值。 如果我们尝试编辑具有其 或 列的值的产品NULL,我们将得到一个ArgumentOutOfRangeException,其中包含类似于:“Categories”的 SelectedValue,因为它不存在于项列表中。SupplierIDCategoryID此外,目前无法将产品类别或供应商价值从非NULL值更改为NULL非值。

若要支持 NULL 类别和供应商 DropDownLists 的值,我们需要添加其他 ListItem。 我已选择使用 (None) 作为 Text 此值 ListItem,但你可以根据需要将其更改为其他 (,例如空字符串) 。 最后,请记住将 DropDownList 设置为 AppendDataBoundItemsTrue;如果忘记这样做,绑定到 DropDownList 的类别和供应商将覆盖静态添加 ListItem的 。

进行这些更改后,DataList 中的 EditItemTemplate DropDownLists 标记应如下所示:

<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静态 可以通过Designer或直接通过声明性语法添加到 DropDownList。 添加 DropDownList 项以表示数据库 NULL 值时,请务必通过声明性语法添加 ListItem 。 如果在Designer中使用ListItem集合编辑器,则当分配空字符串时,生成的声明性语法将完全省略Value该设置,从而创建声明性标记,如:<asp:ListItem>(None)</asp:ListItem>。 虽然这看起来可能无害,但缺失 Value 会导致 DropDownList 在其位置使用 Text 属性值。 这意味着,如果 NULLListItem 选择此选项,则将尝试将值 (None) 分配给产品数据字段 (CategoryIDSupplierID,在本教程) ,这将导致异常。 通过显式设置 Value="",当选择 时NULLListItem,将向产品数据字段分配一个NULL值。

花点时间通过浏览器查看进度。 编辑产品时,请注意 Categories ,和 Suppliers DropDownLists 在 DropDownList 的开头都有一个“ (无) ”选项。

“类别”和“供应商”下拉列表列表包括“无 (”) 选项

图 10:和 CategoriesSuppliers DropDownLists 包括“无 (”) 选项 (单击以查看全尺寸图像)

若要将“ (无) ”选项保存为数据库 NULL 值,需要返回到 UpdateCommand 事件处理程序。 将 categoryIDValuesupplierIDValue 变量更改为可以为 null 的整数,并仅当 DropDownList s SelectedValue 不是空字符串时为其赋值Nothing

Dim categoryIDValue As Nullable(Of Integer) = Nothing
If Not String.IsNullOrEmpty(categories.SelectedValue) Then
    categoryIDValue = Convert.ToInt32(categories.SelectedValue)
End If
Dim supplierIDValue As Nullable(Of Integer) = Nothing
If Not String.IsNullOrEmpty(suppliers.SelectedValue) Then
    supplierIDValue = Convert.ToInt32(suppliers.SelectedValue)
End If

通过此更改,如果用户从任一Nothing下拉列表中选择了“无) (”选项(对应于NULL数据库值),则会将 UpdateProduct 值传递到 BLL 方法中。

总结

在本教程中,我们了解了如何创建更复杂的 DataList 编辑界面,该界面包括三个不同的输入 Web 控件一个 TextBox、两个 DropDownList 和一个 CheckBox 以及验证控件。 生成编辑界面时,无论使用何种 Web 控件,步骤都是相同的:首先将 Web 控件添加到 DataList; EditItemTemplate使用数据绑定语法为相应的数据字段值分配相应的 Web 控件属性;并在事件处理程序中 UpdateCommand 以编程方式访问 Web 控件及其相应属性, 将其值传递到 BLL。

创建编辑界面时,无论它只由 TextBox 或不同 Web 控件的集合组成,请务必正确处理数据库 NULL 值。 在考虑 NULL 时,必须不仅在编辑界面中正确显示现有 NULL 值,而且必须提供一种将值标记为 NULL的方法。 对于 DataLists 中的 DropDownLists,这通常意味着添加一个静态 ListItem ,其 Value 属性显式设置为空字符串 (Value="") ,并将一些代码添加到 UpdateCommand 事件处理程序,以确定是否 NULL``ListItem 选择了 。

编程快乐!

关于作者

斯科特·米切尔是七本 ASP/ASP.NET 书籍的作者和 4GuysFromRolla.com 的创始人,自 1998 年以来一直在使用 Microsoft Web 技术。 Scott 担任独立顾问、培训师和作家。 他的最新一本书是 山姆斯在 24 小时内 ASP.NET 2.0。 可以在 上mitchell@4GuysFromRolla.com联系他,也可以通过他的博客(可在 中找到http://ScottOnWriting.NET)。

特别感谢

本教程系列由许多有用的审阅者审阅。 本教程的主要审阅者是丹尼斯·帕特森、大卫·苏鲁和兰迪·施密特。 有兴趣查看我即将发布的 MSDN 文章? 如果是,请在 处mitchell@4GuysFromRolla.com放置一行。