在 DataList (C#) 中编辑和删除数据概述

作者 :Scott Mitchell

下载 PDF

虽然 DataList 缺乏内置的编辑和删除功能,但本教程将介绍如何创建支持编辑和删除其基础数据的 DataList。

简介

插入、更新和删除数据概述 教程中,我们介绍了如何使用应用程序体系结构、ObjectDataSource 以及 GridView、DetailsView 和 FormView 控件插入、更新和删除数据。 使用 ObjectDataSource 和这三个数据 Web 控件时,实现简单的数据修改接口是一个快照,只需勾选智能标记中的复选框即可。 无需编写代码。

遗憾的是,DataList 缺少 GridView 控件中固有的内置编辑和删除功能。 缺少此功能的部分原因在于,当声明性数据源控件和无代码数据修改页不可用时,DataList 是以前版本的 ASP.NET 的遗物。 虽然 ASP.NET 2.0 中的 DataList 不提供与 GridView 相同的现成数据修改功能,但我们可以使用 ASP.NET 1.x 技术来包含此类功能。 此方法需要一些代码,但正如本教程中所示,DataList 提供了一些事件和属性来帮助完成此过程。

本教程介绍如何创建支持编辑和删除其基础数据的 DataList。 未来的教程将介绍更高级的编辑和删除方案,包括输入字段验证、正常处理从数据访问层或业务逻辑层引发的异常等。

注意

与 DataList 一样,Repeater 控件缺少用于插入、更新或删除的现成功能。 虽然可以添加此类功能,但 DataList 包括中继器中找不到的属性和事件,这些属性和事件可简化此类功能的添加。 因此,本教程和将来查看编辑和删除的内容将严格关注 DataList。

步骤 1:创建编辑和删除教程网页

在开始探索如何更新和删除 DataList 中的数据之前,让我们先花点时间在网站项目中创建本教程和后续几个页面所需的 ASP.NET 页面。 首先添加名为 EditDeleteDataList的新文件夹。 接下来,将以下 ASP.NET 页添加到该文件夹,确保将每个页面与 Site.master 母版页相关联:

  • Default.aspx
  • Basics.aspx
  • BatchUpdate.aspx
  • ErrorHandling.aspx
  • UIValidation.aspx
  • CustomizedUI.aspx
  • OptimisticConcurrency.aspx
  • ConfirmationOnDelete.aspx
  • UserLevelAccess.aspx

为教程添加 ASP.NET 页

图 1:为教程添加 ASP.NET 页

与其他文件夹中一样, Default.aspxEditDeleteDataList 文件夹中列出了其部分中的教程。 回想一下, SectionLevelTutorialListing.ascx 用户控件提供此功能。 因此,将此用户控件Default.aspx从解决方案资源管理器拖到页面设计视图中,将其添加到 。

将 SectionLevelTutorialListing.ascx 用户控件添加到 Default.aspx

图 2:将 SectionLevelTutorialListing.ascx 用户控件添加到 Default.aspx (单击以查看全尺寸图像)

最后,将页面作为条目添加到文件中 Web.sitemap 。 具体而言,使用 DataList 和 Repeater <siteMapNode>在 Master/Detail Reports 后面添加以下标记:

<siteMapNode
    title="Editing and Deleting with the DataList"
    description="Samples of Reports that Provide Editing and Deleting Capabilities"
    url="~/EditDeleteDataList/Default.aspx" >
    <siteMapNode
        title="Basics"
        description="Examines the basics of editing and deleting with the
                     DataList control."
        url="~/EditDeleteDataList/Basics.aspx" />
    <siteMapNode
        title="Batch Update"
        description="Examines how to update multiple records at once in a
                     fully-editable DataList."
        url="~/EditDeleteDataList/BatchUpdate.aspx" />
    <siteMapNode
        title="Error Handling"
        description="Learn how to gracefully handle exceptions raised during the
                     data modification workflow."
        url="~/EditDeleteDataList/ErrorHandling.aspx" />
    <siteMapNode
        title="Adding Data Entry Validation"
        description="Help prevent data entry errors by providing validation."
        url="~/EditDeleteDataList/UIValidation.aspx" />
    <siteMapNode
        title="Customize the User Interface"
        description="Customize the editing user interfaces."
        url="~/EditDeleteDataList/CustomizedUI.aspx" />
    <siteMapNode
        title="Optimistic Concurrency"
        description="Learn how to help prevent simultaneous users from
                     overwritting one another s changes."
        url="~/EditDeleteDataList/OptimisticConcurrency.aspx" />
    <siteMapNode
        title="Confirm On Delete"
        description="Prompt a user for confirmation when deleting a record."
        url="~/EditDeleteDataList/ConfirmationOnDelete.aspx" />
    <siteMapNode
        title="Limit Capabilities Based on User"
        description="Learn how to limit the data modification functionality
                     based on the user s role or permissions."
        url="~/EditDeleteDataList/UserLevelAccess.aspx" />
</siteMapNode>

更新 Web.sitemap后,请花点时间通过浏览器查看教程网站。 左侧菜单现在包含 DataList 编辑和删除教程的项。

站点地图现在包括 DataList 编辑和删除教程的条目

图 3:站点地图现在包含 DataList 编辑和删除教程的条目

步骤 2:检查更新和删除数据的技术

使用 GridView 编辑和删除数据非常简单,因为 GridView 和 ObjectDataSource 在封面下协同工作。 如 检查与插入、更新和删除关联的事件 教程中所述,单击行的“更新”按钮时,GridView 会自动将其使用双向数据绑定的 UpdateParameters 字段分配给其 ObjectDataSource 的集合,然后调用该 ObjectDataSource 方法 Update()

可悲的是,DataList 不提供任何此类内置功能。 我们有责任确保将用户的值分配给 ObjectDataSource 的参数,并调用其 Update() 方法。 为了帮助我们完成此工作,DataList 提供了以下属性和事件:

  • 更新DataKeyField或删除 属性时,我们需要能够唯一标识 DataList 中的每个项。 将此属性设置为所显示数据的主键字段。 这样做将使用每个 DataList 项的指定值填充 DataList 集合DataKeysDataKeyField
  • 单击EditCommand属性设置为“编辑”的 CommandName Button、LinkButton 或 ImageButton 时,将触发事件。
  • 单击CancelCommand属性设置为“取消”的 CommandName Button、LinkButton 或 ImageButton 时,将触发事件。
  • 单击UpdateCommand属性设置为“更新”的 CommandName Button、LinkButton 或 ImageButton 时,将触发事件。
  • 单击DeleteCommand属性设置为“删除”的 CommandName Button、LinkButton 或 ImageButton 时,将触发事件。

使用这些属性和事件,可以使用四种方法来更新和删除 DataList 中的数据:

  1. 使用 ASP.NET 1.x 技术 ,DataList 存在于 ASP.NET 2.0 和 ObjectDataSources 之前,并且能够通过编程方式完全更新和删除数据。 此方法完全放弃 ObjectDataSource,并要求我们直接从业务逻辑层将数据绑定到 DataList,无论是检索要显示的数据,还是在更新或删除记录时。
  2. 在页面上使用单个 ObjectDataSource 控件进行选择、更新和删除, 而 DataList 缺少 GridView 固有的编辑和删除功能,我们没有理由不能自行添加它们。 使用此方法时,我们使用 ObjectDataSource,就像 GridView 示例中一样,但必须为 DataList 事件 UpdateCommand 创建事件处理程序,在该事件中设置 ObjectDataSource 的参数并调用其 Update() 方法。
  3. 使用 ObjectDataSource 控件进行选择,但在使用选项 2 时直接针对 BLL 进行更新和删除 ,我们需要在 事件中 UpdateCommand 编写一些代码,分配参数值等。 相反,我们可以坚持使用 ObjectDataSource 进行选择,但直接对 BLL (进行更新和删除调用,如使用选项 1) 。 在我看来,通过与 BLL 直接交互来更新数据比分配 ObjectDataSource UpdateParameters 并调用其 Update() 方法更易读的代码。
  4. 通过 Multiple ObjectDataSources 使用声明性手段 ,前三种方法都需要一些代码。 如果希望尽可能多地使用声明性语法,最后一个选项是在页面上包含多个 ObjectDataSource。 第一个 ObjectDataSource 从 BLL 检索数据并将其绑定到 DataList。 为了进行更新,添加了另一个 ObjectDataSource,但直接在 DataList 的 中添加 EditItemTemplate。 若要包含删除支持,还需要在 中 ItemTemplate另一个 ObjectDataSource。 使用此方法,这些嵌入的 ObjectDataSource 用于 ControlParameters 以声明方式将 ObjectDataSource 的参数绑定到用户输入控件 (,而无需在 DataList 的 UpdateCommand 事件处理程序) 中以编程方式指定它们。 此方法仍需要一些代码,我们需要调用嵌入的 ObjectDataSource 或 Update()Delete() 命令,但所需的代码远远低于其他三种方法。 此处的缺点是,多个 ObjectDataSources 使页面变得混乱,损害了整体可读性。

如果强制只使用其中一种方法,我会选择选项 1,因为它提供了最大的灵活性,并且 DataList 最初设计用于适应此模式。 虽然 DataList 已扩展为与 ASP.NET 2.0 数据源控件配合使用,但它没有 GridView、DetailsView 和 FormView) (官方 ASP.NET 2.0 数据 Web 控件的所有扩展点或功能。 不过,选项 2 到 4 并非没有优点。

本和将来的编辑和删除教程将使用 ObjectDataSource 检索要显示的数据,并直接调用 BLL 以更新和删除 (选项 3) 的数据。

步骤 3:添加 DataList 并配置其 ObjectDataSource

在本教程中,我们将创建一个列出产品信息的 DataList,并针对每个产品为用户提供编辑名称和价格以及完全删除产品的功能。 具体而言,我们将使用 ObjectDataSource 检索要显示的记录,但通过与 BLL 直接交互来执行更新和删除操作。 在担心对 DataList 实现编辑和删除功能之前,让我们先获取页面,以在只读界面中显示产品。 由于我们在前面的教程中检查了这些步骤,因此我将快速完成这些步骤。

首先打开 文件夹中的页面Basics.aspxEditDeleteDataList,然后从“设计”视图向页面添加 DataList。 接下来,从 DataList 的智能标记中创建新的 ObjectDataSource。 由于我们正在处理产品数据,因此请将其配置为使用 ProductsBLL 类。 若要检索 所有 产品,请在 GetProducts() SELECT 选项卡中选择 方法。

将 ObjectDataSource 配置为使用 ProductsBLL 类

图 4:将 ObjectDataSource 配置为使用 ProductsBLL 类 (单击以查看全尺寸图像)

使用 GetProducts () 方法返回产品信息

图 5:使用 GetProducts() 方法返回产品信息 (单击以查看全尺寸图像)

DataList(与 GridView 一样)不是用于插入新数据的设计。因此,请从“插入”选项卡的下拉列表中选择“ (无) ”选项。此外,为“更新”和“删除”选项卡选择“ (”无“) ,因为更新和删除将通过 BLL 以编程方式执行。

确认 ObjectDataSource 的 INSERT、UPDATE 和 DELETE 选项卡中的 Drop-Down Lists 设置为“无 (”)

图 6:确认 ObjectDataSource 的 INSERT、UPDATE 和 DELETE 选项卡中的 Drop-Down Lists 设置为“无 (”) (单击以查看全尺寸图像)

配置 ObjectDataSource 后,单击“完成”,返回到Designer。 正如我们在过去示例中所看到的,完成 ObjectDataSource 配置时,Visual Studio 会自动为 DropDownList 创建 , ItemTemplate 并显示每个数据字段。 将此 ItemTemplate 替换为仅显示产品名称和价格的 。 此外,将 RepeatColumns 属性设置为 2。

注意

插入、更新和删除数据概述 教程中所述,使用 ObjectDataSource 修改数据时,体系结构要求从 ObjectDataSource 声明性标记中删除 OldValuesParameterFormatString 属性, (或将其重置为其默认值, {0}) 。 但是,在本教程中,我们仅使用 ObjectDataSource 来检索数据。 因此,我们不需要修改 ObjectDataSource 的 OldValuesParameterFormatString 属性值 (尽管这样做不会) 造成损害。

将默认 DataList 替换为自定义的 DataList ItemTemplate 后,页面上的声明性标记应如下所示:

<asp:DataList ID="DataList1" runat="server" DataKeyField="ProductID"
    DataSourceID="ObjectDataSource1" RepeatColumns="2">
    <ItemTemplate>
        <h5>
            <asp:Label runat="server" ID="ProductNameLabel"
                Text='<%# Eval("ProductName") %>'></asp:Label>
        </h5>
        Price: <asp:Label runat="server" ID="Label1"
                    Text='<%# Eval("UnitPrice", "{0:C}") %>' />
        <br />
        <br />
    </ItemTemplate>
</asp:DataList>
<asp:ObjectDataSource ID="ObjectDataSource1" runat="server"
    SelectMethod="GetProducts" TypeName="ProductsBLL"
    OldValuesParameterFormatString="original_{0}">
</asp:ObjectDataSource>

花点时间通过浏览器查看进度。 如图 7 所示,DataList 在两列中显示每个产品的产品名称和单价。

产品名称和价格显示在 Two-Column DataList 中

图 7:产品名称和价格显示在 Two-Column DataList (单击以查看全尺寸图像)

注意

DataList 具有许多更新和删除过程所需的属性,这些值存储在视图状态中。 因此,在生成支持编辑或删除数据的 DataList 时,必须启用 DataList 的视图状态。

精明的读者可能记得,在创建可编辑的 GridViews、DetailsViews 和 FormViews 时,我们能够禁用视图状态。 这是因为 ASP.NET 2.0 Web 控件可以包含 控件状态,该状态在视图状态等回发中持久保存,但被认为是必要的。

在 GridView 中禁用视图状态只是省略了普通状态信息,但会保留控制状态 (,其中包括编辑和删除) 所需的状态。 DataList 是在 ASP.NET 1.x 时间范围内创建的,它不使用控制状态,因此必须启用视图状态。 有关 控件状态 的用途及其与视图状态的不同之处的详细信息,请参阅控件状态与视图状态。

步骤 4:添加编辑用户界面

GridView 控件由一组字段组成, (BoundFields、CheckBoxFields、TemplateFields 等) 。 这些字段可以根据其模式调整其呈现的标记。 例如,在只读模式下,BoundField 将其数据字段值显示为文本;当处于编辑模式时,它会呈现一个 TextBox Web 控件,该控件的 Text 属性被分配有数据字段值。

另一方面,DataList 使用模板呈现其项。 只读项使用 呈现, ItemTemplate 而编辑模式下的项则通过 EditItemTemplate呈现。 此时,DataList 只有 一个 ItemTemplate。 若要支持项级编辑功能,我们需要添加一个 EditItemTemplate ,其中包含要为可编辑项显示的标记。 在本教程中,我们将使用 TextBox Web 控件来编辑产品名称和单价。

EditItemTemplate可以通过声明方式或通过Designer (从 DataList 智能标记) 选择“编辑模板”选项来创建 。 若要使用“编辑模板”选项,请先单击智能标记中的“编辑模板”链接,然后从下拉列表中选择 EditItemTemplate 该项。

选择使用 DataList s EditItemTemplate

图 8:选择使用 DataList (EditItemTemplate单击以查看全尺寸图像)

接下来,键入“产品名称:”和“价格:”,然后将两个 TextBox 控件从工具箱拖到EditItemTemplateDesigner界面中。 将 TextBoxes ID 属性设置为 ProductNameUnitPrice

为产品名称和价格添加 TextBox

图 9:为“产品名称”和“价格”添加 TextBox (单击以查看全尺寸图像)

我们需要将相应的产品数据字段值绑定到 Text 两个 TextBox 的属性。 在 TextBoxs 智能标记中,单击“编辑数据绑定”链接,然后将相应的数据字段与 Text 属性相关联,如图 10 所示。

注意

将数据 UnitPrice 字段绑定到 price TextBox s Text 字段时,可以将其格式化为货币值 ({0:C}) 、 () {0:N} 的一般数字,或将其设置为未格式化。

将 ProductName 和 UnitPrice 数据字段绑定到 TextBox 的文本属性

图 10:将 ProductNameUnitPrice 数据字段绑定到 Text TextBox 的属性

请注意,图 10 中的“编辑数据绑定”对话框 如何不包括 在 GridView 或 DetailsView 中编辑 TemplateField 或 FormView 中的模板时存在的双向数据绑定复选框。 双向数据绑定功能允许在插入或UpdateParameters更新数据时自动将输入到输入 Web 控件的值分配给相应的 ObjectDataSource sInsertParameters。 DataList 不支持双向数据绑定,我们将在本教程的后面部分看到,在用户进行更改并准备好更新数据后,我们需要以编程方式访问这些 TextBoxes Text 属性,并将其值传递到 类中的ProductsBLL相应UpdateProduct方法。

最后,我们需要将“更新”和“取消”按钮添加到 EditItemTemplate。 正如我们在 主控/详细信息使用带详细信息数据列表的主记录项目符号列表 教程中看到的那样,当从 Repeater 或 DataList 内单击设置了属性 CommandName 的 Button、LinkButton 或 ImageButton 时,将引发 Repeater 或 DataList 事件 ItemCommand 。 对于 DataList,如果 CommandName 属性设置为特定值,则也可能引发其他事件。 特殊 CommandName 属性值包括:

  • 取消引发 CancelCommand 事件
  • 编辑引发 EditCommand 事件
  • 更新引发 UpdateCommand 事件

请记住,除了 事件之外,还会引发ItemCommand这些事件。

将 添加到 EditItemTemplate 两个按钮 Web 控件,其中 CommandName 一个控件设置为“更新”,另一个设置为“取消”。 添加这两个按钮 Web 控件后,Designer应如下所示:

显示 DataList EditItemTemplate 的屏幕截图,其中添加了“更新”和“取消”按钮。

图 11:将“更新”和“取消”按钮添加到 EditItemTemplate “ (单击以查看全尺寸图像)

完成之后, EditItemTemplate DataList 的声明性标记应如下所示:

<asp:DataList ID="DataList1" runat="server" DataKeyField="ProductID"
    DataSourceID="ObjectDataSource1" RepeatColumns="2">
    <ItemTemplate>
        <h5>
            <asp:Label runat="server" ID="ProductNameLabel"
                Text='<%# Eval("ProductName") %>' />
        </h5>
        Price: <asp:Label runat="server" ID="Label1"
                    Text='<%# Eval("UnitPrice", "{0:C}") %>' />
        <br />
        <br />
    </ItemTemplate>
    <EditItemTemplate>
        Product name:
            <asp:TextBox ID="ProductName" runat="server"
                Text='<%# Eval("ProductName") %>' /><br />
        Price:
            <asp:TextBox ID="UnitPrice" runat="server"
                Text='<%# Eval("UnitPrice", "{0:C}") %>' /><br />
        <br />
        <asp:Button ID="UpdateProduct" runat="server"
            CommandName="Update" Text="Update" /> 
        <asp:Button ID="CancelUpdate" runat="server"
            CommandName="Cancel" Text="Cancel" />
    </EditItemTemplate>
</asp:DataList>

步骤 5:添加管道以进入编辑模式

此时,DataList 有一个通过其 EditItemTemplate定义的编辑界面;但是,目前访问我们的页面的用户无法指示他想要编辑产品的信息。 我们需要向每个产品添加一个“编辑”按钮,单击后,该按钮将 DataList 项呈现在编辑模式下。 首先,通过 Designer 或以声明方式将“编辑”按钮添加到 ItemTemplate。 请务必将“编辑”按钮的 CommandName 属性设置为“编辑”。

添加此“编辑”按钮后,请花点时间通过浏览器查看页面。 添加此项后,每个产品一览都应包含一个“编辑”按钮。

显示 DataList EditItemTemplate 的屏幕截图,其中添加了“编辑”按钮。

图 12:将“更新”和“取消”按钮添加到 EditItemTemplate “ (单击以查看全尺寸图像)

单击该按钮会导致回发,但 不会 将产品列表置于编辑模式。 若要使产品可编辑,我们需要:

  1. 将 DataList 属性EditItemIndex设置为刚刚单击“编辑”按钮的 的索引DataListItem
  2. 将数据重新绑定到 DataList。 重新呈现 DataList 时, DataListItemItemIndex 与 DataList EditItemIndex 相对应的 将使用其 EditItemTemplate呈现。

由于在单击“编辑”按钮时会触发 DataList 事件 EditCommand ,因此使用以下代码创建 EditCommand 事件处理程序:

protected void DataList1_EditCommand(object source, DataListCommandEventArgs e)
{
    // Set the DataList's EditItemIndex property to the
    // index of the DataListItem that was clicked
    DataList1.EditItemIndex = e.Item.ItemIndex;
    // Rebind the data to the DataList
    DataList1.DataBind();
}

事件处理程序 EditCommand 作为其第二个输入参数传入类型的 DataListCommandEventArgs 对象中,该对象包含对 DataListItem 单击其“编辑”按钮 (e.Item) 的引用。 事件处理程序首先将 DataList 设置为EditItemIndexItemIndexDataListItem编辑的 ,然后通过调用 DataList 方法DataBind()将数据重新绑定到 DataList。

添加此事件处理程序后,在浏览器中重新访问页面。 单击“编辑”按钮现在使单击的产品可编辑 (请参阅图 13) 。

单击“编辑”按钮使产品可编辑

图 13:单击“编辑”按钮使产品可编辑 (单击以查看全尺寸图像)

步骤 6:保存用户的更改

此时,单击已编辑的产品“更新”或“取消”按钮没有任何作用;若要添加此功能,我们需要为 DataList UpdateCommandCancelCommand 事件创建事件处理程序。 首先创建 CancelCommand 事件处理程序,该事件处理程序将在单击已编辑的产品的“取消”按钮时执行,并且它的任务是将 DataList 返回到其预编辑状态。

若要让 DataList 在只读模式下呈现其所有项,我们需要:

  1. 将 DataList 属性EditItemIndex设置为不存在DataListItem索引的索引。 -1 是一个安全的选择,因为 DataListItem 索引从 开始 0
  2. 将数据重新绑定到 DataList。 由于没有 DataListItemItemIndex es 对应于 DataList s EditItemIndex,因此整个 DataList 将以只读模式呈现。

可以使用以下事件处理程序代码完成这些步骤:

protected void DataList1_CancelCommand(object source, DataListCommandEventArgs e)
{
    // Set the DataList's EditItemIndex property to -1
    DataList1.EditItemIndex = -1;
    // Rebind the data to the DataList
    DataList1.DataBind();
}

添加此项后,单击“取消”按钮会将 DataList 返回到其预编辑状态。

我们需要完成的最后一个事件处理程序是 UpdateCommand 事件处理程序。 此事件处理程序需要:

  1. 以编程方式访问用户输入的产品名称和价格以及编辑的产品 ProductID
  2. 通过在 类中ProductsBLL调用相应的UpdateProduct重载来启动更新过程。
  3. 将 DataList 属性EditItemIndex设置为不存在DataListItem索引的索引。 -1 是一个安全的选择,因为 DataListItem 索引从 开始 0
  4. 将数据重新绑定到 DataList。 由于没有 DataListItemItemIndex es 对应于 DataList s EditItemIndex,因此整个 DataList 将以只读模式呈现。

步骤 1 和 2 负责保存用户的更改;保存更改后,步骤 3 和 4 会将 DataList 返回到其预编辑状态,并且与事件处理程序中 CancelCommand 执行的步骤相同。

若要获取更新的产品名称和价格,需要使用 FindControl 方法以编程方式引用 中的 EditItemTemplateTextBox Web 控件。 我们还需要获取已编辑的产品 ProductID 值。 最初将 ObjectDataSource 绑定到 DataList 时,Visual Studio 将 DataList 属性 DataKeyField 分配给数据源 (ProductID) 的主键值。 然后,可以从 DataList 集合 DataKeys 中检索此值。 请花点时间确保 属性 DataKeyField 确实设置为 ProductID

以下代码实现四个步骤:

protected void DataList1_UpdateCommand(object source, DataListCommandEventArgs e)
{
    // Read in the ProductID from the DataKeys collection
    int productID = Convert.ToInt32(DataList1.DataKeys[e.Item.ItemIndex]);
    // Read in the product name and price values
    TextBox productName = (TextBox)e.Item.FindControl("ProductName");
    TextBox unitPrice = (TextBox)e.Item.FindControl("UnitPrice");
    string productNameValue = null;
    if (productName.Text.Trim().Length > 0)
        productNameValue = productName.Text.Trim();
    decimal? unitPriceValue = null;
    if (unitPrice.Text.Trim().Length > 0)
        unitPriceValue = Decimal.Parse(unitPrice.Text.Trim(),
            System.Globalization.NumberStyles.Currency);
    // Call the ProductsBLL's UpdateProduct method...
    ProductsBLL productsAPI = new ProductsBLL();
    productsAPI.UpdateProduct(productNameValue, unitPriceValue, productID);
    // Revert the DataList back to its pre-editing state
    DataList1.EditItemIndex = -1;
    DataList1.DataBind();
}

事件处理程序首先从DataKeys集合中读取已编辑的产品ProductID。 接下来,引用 中的 EditItemTemplate 两个 TextBox,其 Text 属性存储在局部变量 productNameValueunitPriceValue中。 我们使用 Decimal.Parse() 方法从 UnitPrice TextBox 读取值,以便如果输入的值具有货币符号,仍可将其正确转换为 Decimal 值。

注意

如果 TextBoxes Text 属性指定了值,则 和 TextBoxes 中的值ProductNameUnitPrice仅分配给 productNameValue 和 unitPriceValue 变量。 否则,值 Nothing 用于变量,其效果是使用数据库 NULL 值更新数据。 也就是说,我们的代码处理将空字符串转换为数据库 NULL 值,这是 GridView、DetailsView 和 FormView 控件中编辑界面的默认行为。

读取值后, ProductsBLL 将调用 类 s UpdateProduct 方法,并传入产品名称、价格和 ProductID。 事件处理程序通过使用与事件处理程序中 CancelCommand 完全相同的逻辑将 DataList 返回到其预编辑状态来完成。

完成 EditCommandCancelCommandUpdateCommand 事件处理程序后,访问者可以编辑产品的名称和价格。 图 14-16 显示了此编辑工作流的运行情况。

首次访问页面时,所有产品都处于 Read-Only 模式

图 14:首次访问页面时,所有产品都处于 Read-Only 模式 (单击以查看全尺寸图像)

若要更新产品名称或价格,请单击“编辑”按钮

图 15:若要更新产品名称或价格,请单击“编辑”按钮 (单击以查看全尺寸图像)

更改值后,单击“更新”以返回到 Read-Only 模式

图 16:更改值后,单击“更新”以返回到 Read-Only 模式 (单击以查看全尺寸图像)

步骤 7:添加删除功能

向 DataList 添加删除功能的步骤与添加编辑功能的步骤类似。 简言之,我们需要在单击时将“删除”按钮添加到 ItemTemplate 该按钮:

  1. 通过 DataKeys 集合读取相应产品的 ProductID
  2. 通过调用 ProductsBLL 类 s DeleteProduct 方法执行删除。
  3. 将数据重新绑定到 DataList。

首先,将“删除”按钮添加到 ItemTemplate

单击时,如果 CommandName 按钮为“编辑”、“更新”或“取消”,则会引发 DataList 事件 ItemCommand 以及其他事件 (例如,在使用“编辑” EditCommand 时,还会引发) 事件。 同样,DataList CommandName 中属性设置为 Delete 的任何 Button、LinkButton 或 ImageButton 都会导致 DeleteCommand 事件与) 一起 ItemCommand 触发 (。

在 中的 ItemTemplate“编辑”按钮旁边添加一个“删除”按钮,将其 CommandName 属性设置为“删除”。 添加此 Button 控件后,DataList 的 ItemTemplate 声明性语法应如下所示:

<ItemTemplate>
    <h5>
        <asp:Label runat="server" ID="ProductNameLabel"
            Text='<%# Eval("ProductName") %>' />
    </h5>
    Price: <asp:Label runat="server" ID="Label1"
                Text='<%# Eval("UnitPrice", "{0:C}") %>' />
    <br />
    <asp:Button runat="server" id="EditProduct" CommandName="Edit"
        Text="Edit" />
     
    <asp:Button runat="server" id="DeleteProduct" CommandName="Delete"
        Text="Delete" />
    <br />
    <br />
</ItemTemplate>

接下来,使用以下代码为 DataList 事件 DeleteCommand 创建事件处理程序:

protected void DataList1_DeleteCommand(object source, DataListCommandEventArgs e)
{
    // Read in the ProductID from the DataKeys collection
    int productID = Convert.ToInt32(DataList1.DataKeys[e.Item.ItemIndex]);
    // Delete the data
    ProductsBLL productsAPI = new ProductsBLL();
    productsAPI.DeleteProduct(productID);
    // Rebind the data to the DataList
    DataList1.DataBind();
}

单击“删除”按钮会导致回发并触发 DataList 事件 DeleteCommand 。 在事件处理程序中,从DataKeys集合中访问单击的产品ProductID值。 接下来,通过调用 ProductsBLL 类 s DeleteProduct 方法删除产品。

删除产品后,请务必将数据重新绑定到 DataList (DataList1.DataBind()) ,否则 DataList 将继续显示刚刚删除的产品。

总结

虽然 DataList 缺少 GridView 享受的点和单击编辑和删除支持,但只需一小段代码即可对其进行增强以包含这些功能。 在本教程中,我们介绍了如何创建包含可删除以及可编辑其名称和价格的两列产品列表。 添加编辑和删除支持是将相应的 Web 控件包含在 和 EditItemTemplateItemTemplate,创建相应的事件处理程序,读取用户输入的值和主键值,并与业务逻辑层交互。

虽然我们在 DataList 中添加了基本的编辑和删除功能,但它缺乏更高级的功能。 例如,没有输入字段验证 - 如果用户输入的价格太昂贵,则在尝试将“太昂贵Decimal”转换为 时将引发Decimal.Parse异常。 同样,如果在更新业务逻辑或数据访问层中的数据时遇到问题,用户会看到标准错误屏幕。 如果不在“删除”按钮上进行任何确认,则意外删除产品的可能性太大。

在将来的教程中,我们将了解如何改进编辑用户体验。

编程快乐!

关于作者

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

特别感谢

本教程系列由许多有用的审阅者审阅。 本教程的主要审阅者是 Zack Jones、Ken Pespisa 和 Randy Schmidt。 有兴趣查看我即将发布的 MSDN 文章? 如果是,请在 处mitchell@4GuysFromRolla.com放置一行。