作者 :斯科特·米切尔
在我们迄今为止创建的接口中,用户可能会不小心单击“删除”按钮而删除数据,因为他们本来是打算单击“编辑”按钮。 在本教程中,我们将添加在单击“删除”按钮时显示的客户端确认对话框。
介绍
在过去的几个教程中,我们了解了如何使用应用程序体系结构、ObjectDataSource 和数据 Web 控件,以提供插入、编辑和删除功能。 到目前为止,我们检查的删除接口是由一个“删除”按钮组成的,单击该按钮会引发页面回发,并调用 ObjectDataSource 的Delete()
方法。 然后,该方法 Delete()
从业务逻辑层调用已配置的方法,该层将调用向下传播到数据访问层,从而向数据库发出实际 DELETE
语句。
虽然此用户界面使访问者能够通过 GridView、DetailsView 或 FormView 控件删除记录,但当用户单击“删除”按钮时,它缺少任何形式的确认。 如果用户在打算单击“编辑”时意外单击“删除”按钮,则会删除要更新的记录。 为了帮助防止这种情况,在本教程中,我们将添加在单击“删除”按钮时显示的客户端确认对话框。
JavaScript confirm(string)
函数将其字符串输入参数显示为模式对话框中的文本,其中包含两个按钮 -“确定”和“取消”(请参阅图 1)。 该 confirm(string)
函数返回一个布尔值,具体取决于单击的按钮(true
如果用户单击“确定”,如果 false
单击“取消”)。
图 1:JavaScript confirm(string)
方法显示一个模态对话框,Client-Side 消息框内容
在表单提交期间,如果从客户端事件处理程序返回值 false
,则取消表单提交。 使用此功能,我们可以让 Delete 按钮的客户端 onclick
事件处理程序返回调用函数 confirm("Are you sure you want to delete this product?")
的值。 如果用户单击“取消”, confirm(string)
将返回 false,从而导致表单提交取消。 如果没有回发,点击“删除”按钮的产品将不会被删除。 但是,如果用户在确认对话框中单击“确定”,则回发将继续不减,产品将被删除。 有关此技术的详细信息,请参阅 使用 JavaScript 方法 confirm()
控制表单提交 。
如果使用模板与使用 CommandField 时相比,添加必要的客户端脚本稍有不同。 因此,在本教程中,我们将查看 FormView 和 GridView 示例。
注释
使用客户端确认技术(如本教程中讨论的确认技术)假定用户所使用的浏览器支持 JavaScript 且已经启用 JavaScript。 如果上述任一假设不适用于特定用户,点击“删除”按钮将立即触发回发操作(不会弹出确认对话框)。
步骤 1:创建支持删除的 FormView
首先,在EditInsertDelete
文件夹中的ConfirmationOnDelete.aspx
页面中添加一个 FormView,并将其绑定到通过ProductsBLL
类的GetProducts()
方法拉取产品信息的新 ObjectDataSource。 同时配置 ObjectDataSource,以便 ProductsBLL
类方法 DeleteProduct(productID)
映射到 ObjectDataSource 的 Delete()
方法,确保 INSERT 和 UPDATE 选项卡下拉列表设置为 (None)。 最后,选中 FormView 智能标记中的“启用分页”复选框。
执行这些步骤后,新的 ObjectDataSource 声明性标记将如下所示:
<asp:ObjectDataSource ID="ObjectDataSource1" runat="server"
DeleteMethod="DeleteProduct" OldValuesParameterFormatString="original_{0}"
SelectMethod="GetProducts" TypeName="ProductsBLL">
<DeleteParameters>
<asp:Parameter Name="productID" Type="Int32" />
</DeleteParameters>
</asp:ObjectDataSource>
与过去未使用乐观并发的示例一样,请花点时间清除 ObjectDataSource 的 OldValuesParameterFormatString
属性。
由于它已绑定到仅支持删除的 ObjectDataSource 控件,因此 FormView ItemTemplate
仅提供“删除”按钮,缺少“新建”和“更新”按钮。 FormView 的声明性标记包含多余的 EditItemTemplate
和 InsertItemTemplate
,可以将其删除。 请花点时间自定义 ItemTemplate
,以便仅显示产品数据字段的子集。 我已将其配置为在供应商和类别名称上方的标题中显示产品的名称(以及“删除”按钮)。
<asp:FormView ID="FormView1" AllowPaging="True" DataKeyNames="ProductID"
DataSourceID="ObjectDataSource1" runat="server">
<ItemTemplate>
<h3><i><%# Eval("ProductName") %></i></h3>
<b>Category:</b>
<asp:Label ID="CategoryNameLabel" runat="server"
Text='<%# Eval("CategoryName") %>'>
</asp:Label><br />
<b>Supplier:</b>
<asp:Label ID="SupplierNameLabel" runat="server"
Text='<%# Eval("SupplierName") %>'>
</asp:Label><br />
<asp:LinkButton ID="DeleteButton" runat="server" CausesValidation="False"
CommandName="Delete" Text="Delete">
</asp:LinkButton>
</ItemTemplate>
</asp:FormView>
通过这些更改,我们有一个功能齐全的网页,允许用户一次切换一个产品,只需单击“删除”按钮即可删除产品。 图 2 显示到目前为止通过浏览器查看进度的屏幕截图。
图 2:FormView 显示有关单个产品的信息(单击以查看全尺寸图像)
步骤 2:从“删除按钮”Client-Side onclick 事件调用 confirm(string) 函数
创建 FormView 后,最后一步是配置“删除”按钮,以便当访问者单击该按钮时,将调用 JavaScript confirm(string)
函数。 可以使用 OnClientClick property
将客户端脚本添加到 Button、LinkButton 或 ImageButton 的客户端onclick
事件,这是对 ASP.NET 2.0 的新增功能。 由于我们想要返回函数的值 confirm(string)
,因此只需将此属性设置为: return confirm('Are you certain that you want to delete this product?');
在此更改后,Delete LinkButton 的声明性语法应如下所示:
<asp:LinkButton ID="DeleteButton" runat="server" CausesValidation="False"
CommandName="Delete" Text="Delete"
OnClientClick="return confirm('Are you certain you want to delete this product?');">
</asp:LinkButton>
就这么简单! 图 3 显示了确认过程的执行截图。 单击“删除”按钮会显示确认对话框。 如果用户点击“取消”,则会取消回传,并且不会删除产品。 但是,如果用户单击“确定”,则回发会继续,并调用 ObjectDataSource s Delete()
方法,最终删除了数据库记录。
注释
传入 JavaScript 函数的 confirm(string)
字符串用撇号(而不是引号)分隔。 在 JavaScript 中,可以使用任一字符分隔字符串。 我们在此处使用引号,以便传入 confirm(string)
的字符串的分隔符不会引入与用于 OnClientClick
属性值的分隔符的歧义性。
图 3:单击“删除”按钮时显示确认(单击以查看全尺寸图像)
步骤 3:在 CommandField 中为“删除”按钮配置 OnClientClick 属性
直接在模板中使用 Button、LinkButton 或 ImageButton 时,只需配置其 OnClientClick
属性以返回 JavaScript confirm(string)
函数的结果即可与其关联确认对话框。 但是,CommandField(用于向 GridView 或 DetailsView 中添加 Delete 按钮的字段)没有可以声明设置的 OnClientClick
属性。 相反,我们必须以编程方式在 GridView 或 DetailsView 的相应 DataBound
事件处理程序中引用“删除按钮”,然后在同一位置设置其 OnClientClick
属性。
注释
在适当的DataBound
事件处理程序中设置 Delete 按钮的OnClientClick
属性时,我们可以访问绑定到当前记录的数据。 这意味着我们可以扩展确认消息以包含有关特定记录的详细信息,例如,“是否确实要删除 Chai 产品?”也可以使用数据绑定语法在模板中进行此类自定义。
为了练习在 CommandField 中设置 OnClientClick
删除按钮的属性,我们将把 GridView 添加到页面中。 将此 GridView 配置为使用 FormView 当前使用的同一 ObjectDataSource 控件。 此外,将 GridView s BoundFields 限制为仅包含产品名称、类别和供应商。 最后,选中 GridView 智能标记中的“启用删除”复选框。 这会将 Columns
CommandField 添加到 GridView 的集合中,并将其 ShowDeleteButton
属性设置为 true
。
进行这些更改后,GridView 的声明性标记应如下所示:
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
DataKeyNames="ProductID" DataSourceID="ObjectDataSource1">
<Columns>
<asp:CommandField ShowDeleteButton="True" />
<asp:BoundField DataField="ProductName" HeaderText="Product"
SortExpression="ProductName" />
<asp:BoundField DataField="CategoryName" HeaderText="Category" ReadOnly="True"
SortExpression="CategoryName" />
<asp:BoundField DataField="SupplierName" HeaderText="Supplier" ReadOnly="True"
SortExpression="SupplierName" />
</Columns>
</asp:GridView>
CommandField 包含一个 Delete LinkButton 实例,可以通过 GridView 的 RowDataBound
事件处理程序以编程方式进行访问。 引用后,我们可以相应地设置其 OnClientClick
属性。 使用以下代码为 RowDataBound
事件创建事件处理程序:
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
// reference the Delete LinkButton
LinkButton db = (LinkButton)e.Row.Cells[0].Controls[0];
// Get information about the product bound to the row
Northwind.ProductsRow product =
(Northwind.ProductsRow) ((System.Data.DataRowView) e.Row.DataItem).Row;
db.OnClientClick = string.Format(
"return confirm('Are you certain you want to delete the {0} product?');",
product.ProductName.Replace("'", @"\'"));
}
}
此事件处理程序适用于数据行(这些行将具有“删除”按钮),并通过以编程方式引用“删除”按钮开始。 一般情况下,请使用以下模式:
ButtonType obj = (ButtonType) e.Row.Cells[commandFieldIndex].Controls[controlIndex];
ButtonType 是 CommandField - Button、LinkButton 或 ImageButton 使用的按钮类型。 默认情况下,CommandField 使用 LinkButtons,但可以通过 CommandField s ButtonType property
进行自定义。
commandFieldIndex 是 GridView 集合Columns
中 CommandField 的序号索引,而 controlIndex 是 CommandField 集合中 Delete 按钮的Controls
索引。
controlIndex 值取决于按钮相对于 CommandField 中的其他按钮的位置。 例如,如果 CommandField 中显示的唯一按钮是“删除”按钮,请使用索引 0。 但是,如果存在位于“删除”按钮之前的“编辑”按钮,请使用索引 2。 使用索引 2 的原因是,因为命令字段在“删除”按钮之前添加了两个控件:“编辑”按钮和用于在“编辑”和“删除”按钮之间添加空格的文本控件。
在我们的例子中,CommandField 使用 LinkButtons,由于它是最左侧的字段,所以 commandFieldIndex 为 0。 由于命令字段中除了“删除”按钮外没有其他按钮,因此我们使用 controlIndex 为 0。
引用 CommandField 中的“删除”按钮后,接下来将获取有关绑定到当前 GridView 行的产品的信息。 最后,我们将 Delete 按钮 s OnClientClick
属性设置为相应的 JavaScript,其中包括产品名称。 因为传入 confirm(string)
函数的 JavaScript 字符串是使用撇号作为分界符的,所以我们必须对出现在产品名称中的任何撇号进行转义。 具体而言,产品名称中的任何撇号都会用"\'
"进行转义。
完成这些更改后,单击 GridView 中的“删除”按钮将显示自定义的确认对话框(请参阅图 4)。 与 FormView 中的确认消息框一样,如果用户单击“取消”,则取消回发,从而阻止删除发生。
注释
此方法还可用于以编程方式访问 DetailsView 中 CommandField 中的“删除”按钮。 但是,对于 DetailsView,你需要为 DataBound
事件创建一个事件处理程序,因为 DetailsView 没有 RowDataBound
事件。
图 4:单击 GridView 的“删除”按钮显示自定义的确认对话框(单击以查看全尺寸图像)
使用模板字段
CommandField 的缺点之一是必须通过索引访问其按钮,并且生成的对象必须强制转换为适当的按钮类型(Button、LinkButton 或 ImageButton)。 使用“魔术数字”和硬编码类型可能会导致在运行时才会被发现的问题。 例如,如果你或其他开发人员在将来的某个时间点(如“编辑”按钮)向 CommandField 添加新按钮或更改 ButtonType
属性,则现有代码仍将编译而不出错,但访问页面可能会导致异常或意外行为,具体取决于代码的编写方式和所做的更改。
另一种方法是将 GridView 和 DetailsView s CommandFields 转换为 TemplateFields。 这将生成一个 TemplateField ItemTemplate
,其中每个命令字段中的按钮都有一个 LinkButton(或 Button 或 ImageButton)。 可以使用以下模式以声明方式分配这些按钮 OnClientClick
属性,就像我们在 FormView 中看到的那样,也可以以编程方式在相应的 DataBound
事件处理程序中访问:
ButtonType obj = (ButtonType) e.Row.FindControl("controlID");
其中 controlID 是按钮属性 ID
的值。 尽管此模式仍需要强制转换的硬编码类型,但它消除了对索引的需求,从而允许布局更改,而不会导致运行时错误。
概要
JavaScript confirm(string)
函数是用于控制表单提交工作流的常用技术。 执行后,该函数会显示一个模式的客户端对话框,其中包含两个按钮:“确定”和“取消”。 如果用户单击“确定”,则 confirm(string)
函数返回 true
;单击“取消”返回 false
。 如果提交过程中事件处理程序返回 false
,则此功能加上浏览器取消表单提交的行为,可用于在删除记录时显示确认消息框。
该confirm(string)
函数可以通过控件的OnClientClick
属性与 Button Web 控件的客户端onclick
事件处理程序相关联。 在模板中使用“删除”按钮时(无论是在 FormView 的模板之一中还是在 DetailsView 或 GridView 中的 TemplateField 中),则可以按声明方式或以编程方式设置此属性,如本教程中所示。
快乐编程!
关于作者
斯科特·米切尔,七本 ASP/ASP.NET 书籍的作者和 4GuysFromRolla.com 的创始人,自1998年以来一直在与Microsoft Web 技术合作。 斯科特担任独立顾问、教练和作家。 他的最新书是 山姆斯教你自己学会 ASP.NET 2.0 在24小时内。 他可以通过 mitchell@4GuysFromRolla.com 联系到。