本文档是 Visual C# 教程 (切换到 Visual Basic 教程)
虽然 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 包含 Repeater 所不具备的一些属性和事件,这些属性和事件可以简化这些功能的添加过程。因此,本教程以及后面与编辑和删除内容相关的教程中,都将注意力集中在 DataList 方面。 步骤1 :创建编辑和删除教程网页在我们就如何从 DataList 中更新和删除数据进行探讨之前,首先让我们先花一些时间在我们的网站计划中创建ASP.NET 页面,在本教程以及接下来的几个教程中,都会需要用到该网站工程。由增加一个新的、名为 EditDeleteDataList 的文件夹开始。接下来,将以下 ASP.NET 页面添加到该文件夹,确保每个页面与 Site.master 母版页相关联:
图1 :为教程添加 ASP.NET 页面 和在其他文件夹中的情况一样,EditDeleteDataList 文件夹中的 Default.aspx 也在自己的部分列出了多个教程。回想一下, SectionLevelTutorialListing.ascx 用户控件提供本功能。因此,将用户控件从 Solution Explorer 拖至页面的设计视图,完成用户控件的添加。 图2 :将SectionLevelTutorialListing.ascx 用户控件添加至 Default.aspx 最后,将页面作为条目添加到 Web.sitemap 文件中。具体来说,将以下标记添加在带有 DataList 和 Repeater <siteMapNode> 的主/ 明细报表之后:
更新Web.sitemap 后,花点时间在浏览器中查看教程网站。现在,左边的菜单包含有用于编辑、插入和删除教程的各项。 图3 :站点地图现在包含用于 DataList 编辑和删除教程的条目 步骤2 :探讨用于更新和删除数据的技术使用 GridView 编辑和删除数据是非常容易的,这是因为,实际上,GridView 和 ObjectDataSource 在一同工作。正如在数据插入、更新和删除概述教程中所讨论的那样,当单击某行的更新按钮后, GridView 自动将其双向数据绑定的字段分配到其 ObjectDataSource 的 UpdateParameters 集合,然后调用该 ObjectDataSource 的 Update() 方法。 不幸的是,DataList 不提供这些中的任何一项内置功能。我们的责任是确保使用用户值为ObjectDataSource 的参数赋值,并且确保调用其 Update() 方法。 DataList 提供了如下属性和事件在这一方面协助我们:
利用这些属性和事件,我们可以使用四种方法从 DataList 中对数据进行更新和删除:
如果必须在这些方式中选择一个的话,我宁愿选择选项 1 ,因为这一方式所提供的灵活性最强,并且 DataList 在已开始就被设计成是与这一形式相互兼容的软件。虽然 DataList 经过改进以便可以和 ASP.NET 2.0 数据源控件一同工作,但是它并不具备“官方版” ASP.NET 2.0 Web 数据控件(GridView 、 DetailsView 和 FormView )所具有的可延伸性特点或特色选项 2 到选项 4 没有任何优点。 本篇编辑与删除教程以及后面的编辑与删除教程将使用ObjectDataSource 用于显示数据的检索,并指示调用命令至 BLL 以进行更新和删除数据(选项 3 )。 步骤3 :添加 DataList 并配置其ObjectDataSource在本篇教程中,我们将创建一个 DataList ,以列出产品信息,并针对每一种产品,为用户提供可以对其名称和价格进行编辑的功能以及完全删除这一产品的功能。具体来说,我们将使用 ObjectDataSource 对显示的记录进行检索,但是通过与 BLL 的直接界面连接进行更新与删除操作。在我们处心积虑的想使 DataList 具备编辑与删除功能之前,首先我们必须有一个页面,以便在只读界面上显示产品。因为我们在前面的教程中已经分析了这些步骤,所以对于这些步骤我会一带而过的进行说明。 首先,在 EditDeleteDataList 文件夹中打开 Basics.aspx 页面,同时从设计视图中为这一页面添加一个DataList 。接下来,从 DataList 的智能标记中创建一个新的 ObjectDataSource 。因为我们正在处理产品数据,所以将其设置为使用 ProductsBLL 类。如果想对所有产品进行检索,在 SELECT 选项卡中选择 GetProducts() 方法。 图4 :配置 ObjectDataSource 使用 ProductsBLL 类 图5 :使用 GetProducts() 方法返回产品信息 DataList 与 GridView 一样,其设计未考虑新数据的插入操作;因此,从 INSERT 选项卡内的下拉菜单中选择 (None) 选项。 因为更新与删除操作将通过 BLL 编码执行,所以对于 UPDATE 与 DELETE 选项卡,也同样选择 (None) 。 图6 :确认 ObjectDataSource 中的INSERT 、UPDATE 和 DELETE 选项卡 内的下拉列表已经设置为 (None) 配置 ObjectDataSource 后,单击“完成”,返回至设计器。正如我们在先前的实例中看到的那样,当完成 ObjectDataSource 配置后,Visual Studio 将会自动为下拉列表创建一个 ItemTemplate 模板,显示每个数据字段。用一个仅显示产品名称和价格的模板取代这一 ItemTemplate 模板。同时将 RepeatColumns 属性设置为 2 。 注意 :正如在数据插入、更新和删除概述教程中所讨论的那样,当使用ObjectDataSource 修改数据时,我们的构架要求必须将 OldValuesParameterFormatString 属性从ObjectDataSource 的声明式标记中移除(或者重置为其默认值 {0} ) 。然而在本篇教程中,我们仅在数据检索中使用 ObjectDataSource 。因此,我们不需要修改 ObjectDataSource 的 OldValuesParameterFormatString 属性值(虽然修改也不会造成什么影响)。 在使用一个定制模板代替默认的DataList ItemTemplate 模板后,页面中的声明式标记应该与如下标记相似:
花点时间在浏览器中查看一下进度。如图7 所示,DataList 以两列显示每个产品的产品名称和单位价格。 图7 :以两列 DataList 显示产品的名称和价格 注意:DataList 有大量的属性需要进行更新和删除,这些属性值都储存在视图状态中。因此,在构建一个支持数据编辑与删除的 DataList 时,激活 DataList 的视图状态十分的重要。 在 GridView 中关闭视图状态只会造成一些细小的状态信息被忽略,但是可以保持控制状态(该状态包括编辑和删除操作所必须的状态)。在 ASP.NET 1.x 时间框架中创建的 Datalist ,不需要利用控制状态,因此必须激活视图状态。有关更多关于控制状态的信息,以及与控制状态和视图状态之间的区别有关的信息,请参见控制状态与视图状态部分。 步骤4 :添加编辑用户界面GridView 控件由字段集(BoundFields 、CheckBoxFields 、TemplateFields 等)组成。这些字段可以根据他们自己的模式调整自身的呈现标记。比如,当处于只读模式时,BoundField 可以以文本显示其数据字段;当处于编辑模式时,BoundField 将呈现那些文本属性被赋予数据字段值的 Web 文本框控件。 另一方面,DataList 使用模板呈现自身的项目。只读项目通过使用ItemTemplate 模板进行呈现,处于编辑模式下的项目通过 EditItemTemplate 模板进行呈现。此时,我们的 DataList 仅有一个 ItemTemplate 模板。若要支持项目范围内的编辑功能,我们需要添加一个 EditItemTemplate 模板,该模板包含要为可编辑项目显示的标记。在本教程中,我们将使用 Web 文本框控件来编辑产品的名称和单位价格。 EditItemTemplate 模板既可以通过声明的方式又可以通过设计器来创建(通过从 DataList 的智能标记中选择“编辑模板”)。要使用 Edit Templates 选项,首先在智能标记中单击“编辑模板”链接,然后从下拉列表中选择 EditItemTemplate 模板项目。 图8 :选择 “与 DataList 的 EditItemTemplate 模板一同工作” 接下来,填写“产品名称” 一栏,和 “价格” 。然后从工具箱中将两个文本框控件拖至设计器的 EditItemTemplate 模板界面中。将文本框的 ID 属性设置为 ProductName 和 UnitPrice。 图9 :为产品的名称和价格添加文本框。 我们需要将相应的产品数据字段值绑定至两个文本框的文本属性中。在文本框的智能标记中,单击 Edit DataBindings 链接,然后将适当的数据字段与文本属性相关联,如图 10 所示。 注意:当将 UnitPrice 数据字段与价格文本框的文本字段进行绑定时,您可以将其格式化为币值 ({0:C}) 、通用数字 ({0:N}) 或保持其未格式化的状态。 图10 :将 ProductName 和 UnitPrice 数据字段与文本框的文本属性相绑定 注意,图 10 中的 “编辑数据绑定” 对话框是如何将 “双向数据绑定” 复选框排除在外的,当编辑 GridView 或 DetailsView 中的一个模板字段或 FormView 中的模板时,“双向数据绑定” 复选框就会出现。在数据插入和更新时,“双向数据绑定”功能允许将键入到 Web 输入控件中的数值自动分配至相应的 ObjectDataSource 插入参数或更新参数内。 DataList 不支持双向数据绑定 — 这一点过一会我们会在本教程中看到,在用户完成改变并准备进行数据更新时,我们将需要通过编程访问文本框的文本属性,并将他们的数值传递至 ProductsBLL 类内适当的 UpdateProduct 方法。 最后,我们需要将更新和取消按钮添加至 EditItemTemplate 模板。正如我们在使用 DataList 和 Bulleted List 创建主/明细报表教程中所看到的那样,当从 Repeater 或 DataList 中单击已设置 CommandName 属性的 Button 、LinkButton 、或 ImageButton 时,将触发 Repeater 或DataList 的 ItemCommand 事件。对于 DataList 来说,如果 CommandName 属性被设定为一个确定值,则可能触发另外一个事件。 其中,特殊的 CommandName 属性值包括:
请牢记,这些事件是除 ItemCommand 事件外的其他触发事件。 在EditItemTemplate 中添加两个 Web 按钮控件,其中一个的 CommandName 设置为 “Update”,另外的一个设置为 “Cancel” 。在添加了这两项 Web 按钮控件后,设计器看起来类似如下图片中的内容: 图11 :在 EditItemTemplate 模板中添加更新与取消按钮 EditItemTemplate 模板完成时,DataList 的声明式标记应该与如下的标记相类似:
步骤5 :在输入编辑模式下添加管道此时,DataList 具有一个通过自身 EditItemTemplate 模板进行定义的编辑界面;然而,在现阶段还没有一种方式可以允许用户访问我们的页面以表示用户想对产品信息进行编辑。我们需要在每个产品中添加一个编辑按钮,当单击该编辑按钮时,可以在编辑模式下对 DataList 项目进行呈现。首先可以通过设计器或采取声明的方式,将一个编辑按钮添加至 ItemTemplate 模板。一定要将编辑按钮的 CommandName 属性设置为“Edit”。 在添加完这一编辑按钮后,花一些时间通过浏览器对页面进行浏览。添加完毕后,每一个产品列表都应该包含一个编辑按钮。 图12 : 在 EditItemTemplate 模板中添加更新与取消按钮 单击按钮 将 引起一个回传,但是不要将产品列表引入编辑模式。为了使得产品可以编辑,我们需要:
因为当单击编辑按钮后,将触发 DataList 的EditCommand 事件,所以使用如下的代码创建一个EditCommand event handler :
EditCommand event handler 以 DataListCommandEventArgs 类型对象传递,作为其第二个输入参数,该参数 包括一个 DataListItem 参考(该 DataListItem 的编辑按钮被单击)(e.Item) 。Event Handler 首先将 DataList 的 EditItemIndex 设置为可编辑 DataListItem 的项目索引,然后通过调用DataList 的 DataBind() 方法,将数据与 DataList 再次进行绑定。 在添加这一Event Handler 后,在浏览器中再次访问该页面。现在单击编辑按钮,就可以对所单击的产品进行编辑(见图 13 )。 图13 :单击编辑按钮,使得产品变成可编辑状态 步骤6:保存用户所做的改变此时,单击已编辑产品的更新或取消按钮不会起任何作用;如果想要添加该功能,我们需要为 DataList 的 UpdateCommand 和 CancelCommand 事件创建 Event Handler 。首先创建 CancelCommand Event Handler ,当单击已编辑产品的取消按钮时,将执行该操作,它还会使 DataList 返回至编辑前的状态。 要使 DataList 在只读模式下呈现其所有的项目,我们需要:
使用如下的Event Handler 代码就可以实现上述步骤:
添加完成之后,单击取消按钮就会将 DataList 返回至编辑前的状态。 我们需要完成的最后一个Event Handler 是 UpdateCommand Event Handler 。该 Event Handler 需要:
步骤 1 和步骤 2 负责对用户所做出的改变进行保存;在所做改变被保存之后,步骤 3 和步骤 4 将 DataList 返回至编辑前的状态,步骤 3 和步骤 4 与在 CancelCommand Event Handler 中所执行的步骤相同。 为了获得已经更新的产品名称和价格,我们需要使用 FindControl 方法,在EditItemTemplate 面板内通过编码为 Web 文本框控件做附注。我们还需要获得已编辑产品的 ProductID 值。我们最初将 ObjectDataSource 与 DataList 相互绑定时, Visual Studio 会将 DataList 的 DataKeyField 属性从数据源 (ProductID) 中分配给主键值。然后可以从 DataList 的 DataKeys 集合中检索该值。花一些时间确保 DataKeyField 属性确实被设置为 ProductID 。 以下的代码会实现四个步骤:
从 DataKeys 集合中读取已编辑产品的 ProductID ,将启动 Event Handler 。接下来,将引用 EditItemTemplate 模板中的两个文本框,他们的文本属性储存在本地变量、ProductNameValue 以及 unitPriceValue 中。我们使用 Decimal.Parse() 方法从 UnitPrice 文本框中读取数值,这样,如果输入的数值中含有货币符号,依然可以转换为十进制数值。 注意:如果已指定了文本框的文本属性值,那么来自 ProductName 和 UnitPrice 文本框中的数值只会分配至 ProductNameValue 变量和 unitPriceValue 变量。否则,变量就会使用一个空值,其结果就是通过数据库 NULL 值对数据进行更新。即,我们的代码将空字符串转换成了数据库 NULL 值,该操作在 GridView 、 DetailsView 和 FormView 控件中是编辑界面的默认行为。 在读取数值后,调用 ProductsBLL 类的 UpdateProduct 方法,传递产品名称、价格以及 ProductID 。通过使用与在 CancelCommand Event Handler中几乎相同的逻辑,将 DataList 返回至编辑前的状态,该 Event Handler也就完成了。 随着 EditCommand 、CancelCommand 和 UpdateCommand Event Handler 的完成,网站的访问者就可以对一种产品的名称和价格进行编辑了。图 14-16 显示了这一编辑操作的流程。 图14 :当第一次访问页面时,所有的产品都处于只读模式 图15 :要更新某种产品的名称或价格,单击编辑按钮 图16 :更改数值后,单击更新返回至只读模式 步骤7 :添加删除功能在 DataList 中添加删除功能的步骤与添加编辑功能的步骤类似。简而言之,我们需要在ItemTemplate 中添加一个删除按钮,当单击时:
我们首先向 ItemTemplate 添加一个删除按钮。 当单击 CommandName 属性为“Edit” 、 “Update” 或 “Cancel” 的按钮时,将触发 DataList 的 ItemCommand 事件和一个额外的事件(比如,当使用 “Edit” 时,将触发 EditCommand 事件)。 与此类似,CommandName 属性设置为“Delete” 的 DataList 中的任何 Button 、LinkButton 或 ImageButton 都会触发 DeleteCommand 事件(同时触发 ItemCommand)。 向ItemTemplate 中编辑按钮的旁边添加一个删除按钮,将其CommandName 属性设置为“Delete” 。添加该按钮控件后,DataList 的 ItemTemplate 声明式语法应该类似如下:
接下来,使用以下代码为 DataList 的DeleteCommand 事件创建Event Handler 。
单击删除按钮引发一个回传,并且激发 DataList 的 DeleteCommand 事件。在 Event Handler 中,从 DataKeys 集合访问被单击产品的 ProductID 值。接下来,调用 ProductsBLL 类的 DeleteProduct 方法,将产品删除。 在将产品删除后,将数据与 DataList 再次绑定(DataList1.DataBind()) 十分重要,否则 DataList 将会继续显示已删除的产品。 小结虽然 DataList 没有 GridView 所具备的单击编辑与删除功能,但是只需要很少的代码就可以增强 DataList ,将这些功能包括在内。在本篇教程中,我们了解了如何创建一个两列的产品列表,从表中可以删除产品并对其名称和价格进行编辑。添加编辑和删除功能用到了ItemTemplate 和 EditItemTemplate 中的相应 Web 控件;是一个创建相应 Event Handler的过程;是一个读取用户输入数值以及主键值的过程;是一个与业务逻辑层进行连接的过程。 虽然我们已经将基本的编辑与删除功能添加至了DataList ,但是 DataList 缺乏更加高级的特性。比如,没有输入字段确认—— 如果用户输入了“价格太高”,当试图将其转换为十进制形式时, Decimal.Parse 就会出现异常。同样,如果在业务逻辑层或数据访问层出现数据更新问题,在用户面前就会出现标准的错误屏幕。而在删除按钮中没有任何形式的确认,也会出现将产品意外删除的情况。 在以后的教程中,我们将就如何提高编辑用户的体验进行讨论。 快乐编程!
|