删除时添加客户端确认 (VB)
在我们目前创建的界面中,用户可能会意外地通过单击“删除”按钮来删除数据,而他们打算单击“编辑”按钮。 在本教程中,我们将添加单击“删除”按钮时出现的客户端确认对话框。
简介
在过去的几个教程中,我们已了解如何协同使用应用程序体系结构、ObjectDataSource 和数据 Web 控件来提供插入、编辑和删除功能。 到目前为止,我们检查的删除接口由“删除”按钮组成,单击该按钮时会导致回发并调用 ObjectDataSource s Delete()
方法。 然后, Delete()
方法从业务逻辑层调用配置的方法,该层将调用向下传播到数据访问层,向数据库发出实际 DELETE
语句。
虽然此用户界面允许访问者通过 GridView、DetailsView 或 FormView 控件删除记录,但当用户单击“删除”按钮时,它缺少任何类型的确认。 如果用户在打算单击“编辑”时意外单击“删除”按钮,则会删除他们打算更新的记录。 为了帮助防止出现这种情况,在本教程中,我们将添加一个客户端确认对话框,该对话框在单击“删除”按钮时显示。
JavaScript confirm(string)
函数将其字符串输入参数显示为模式对话框中的文本,该对话框附带了两个按钮 -“确定”和“取消” (请参阅图 1) 。 如果用户单击“确定”,false
并且单击“取消”) true
,函数confirm(string)
将返回一个布尔值,具体取决于 (单击的按钮。
图 1:JavaScript confirm(string)
方法显示模式 Client-Side 消息框
在表单提交期间,如果从客户端事件处理程序返回 值 false
,则取消表单提交。 使用此功能,我们可以让“删除”按钮客户端 onclick
事件处理程序返回对 confirm("Are you sure you want to delete this product?")
的调用的值。 如果用户单击“取消”, confirm(string)
将返回 false,从而导致表单提交取消。 如果没有回发,则不会删除单击“删除”按钮的产品。 但是,如果用户在确认对话框中单击“确定”,则回发将继续有增无减,产品将被删除。 有关此技术的详细信息 ,请参阅使用 JavaScript 方法 confirm()
控制表单提交 。
如果使用模板,则添加必要的客户端脚本与使用 CommandField 时略有不同。 因此,在本教程中,我们将查看 FormView 和 GridView 示例。
注意
使用客户端确认技术(如本教程中讨论的技术)假设用户访问的浏览器支持 JavaScript,并且已启用 JavaScript。 如果上述任一假设都不适用于特定用户,则单击“删除”按钮将立即导致回发 (不显示确认消息框) 。
步骤 1:创建支持删除的 FormView
首先,将 FormView 添加到 文件夹中的页面ConfirmationOnDelete.aspx
EditInsertDelete
,将其绑定到新的 ObjectDataSource,该对象通过 ProductsBLL
类方法GetProducts()
拉回产品信息。 此外,配置 ObjectDataSource,以便 ProductsBLL
类方法 DeleteProduct(productID)
映射到 ObjectDataSource s 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
以便 仅显示产品数据字段的子集。 我已将我的配置为在其供应商上方的标题中 <h3>
显示产品名称, (类别名称以及“删除”按钮) 。
<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 (字符串) Function
创建 FormView 后,最后一步是配置“删除”按钮,以便访问者单击该按钮时调用 JavaScript confirm(string)
函数。 可以使用 OnClientClick property
将客户端脚本添加到 Button、LinkButton 或 ImageButton s 客户端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 方法 Delete()
,最终删除数据库记录。
注意
传入 JavaScript 函数的 confirm(string)
字符串用撇号分隔 (而不是引号) 。 在 JavaScript 中,可以使用任一字符分隔字符串。 我们在此处使用撇号,以便传入 confirm(string)
的字符串的分隔符不会与用于 OnClientClick
属性值的分隔符引入歧义。
图 3:单击“删除”按钮 (单击以查看全尺寸图像)
步骤 3:为 CommandField 中的“删除”按钮配置 OnClientClick 属性
直接在模板中使用 Button、LinkButton 或 ImageButton 时,只需配置其 属性以返回 JavaScript confirm(string)
函数的结果,即可与其OnClientClick
关联确认对话框。 但是,CommandField(向 GridView 或 DetailsView 添加删除按钮的字段)没有 OnClientClick
可声明性设置的属性。 相反,我们必须以编程方式引用 GridView 或 DetailsView 中相应的 DataBound
事件处理程序中的“删除”按钮,然后在该处设置其 OnClientClick
属性。
注意
在相应的DataBound
事件处理程序中设置“删除”按钮 s OnClientClick
属性时,我们有权访问绑定到当前记录的数据。 这意味着我们可以扩展确认消息以包含有关特定记录的详细信息,例如,“是否确实要删除 Chai 产品?”使用数据绑定语法的模板中也可以进行此类自定义。
若要练习在 CommandField 中设置 OnClientClick
“删除”按钮 () 的属性,请将 GridView 添加到页面。 将此 GridView 配置为使用 FormView 使用的同一 ObjectDataSource 控件。 此外,将 GridView 的 BoundFields 限制为仅包含产品名称、类别和供应商。 最后,检查 GridView 智能标记中的“启用删除”复选框。 这会将 CommandField 添加到 GridView 集合 Columns
,其 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 Sub GridView1_RowDataBound(ByVal sender As Object, _
ByVal e As System.Web.UI.WebControls.GridViewRowEventArgs) _
Handles GridView1.RowDataBound
If e.Row.RowType = DataControlRowType.DataRow Then
' reference the Delete LinkButton
Dim db As LinkButton = CType(e.Row.Cells(0).Controls(0), LinkButton)
' Get information about the product bound to the row
Dim product As Northwind.ProductsRow = _
CType(CType(e.Row.DataItem, System.Data.DataRowView).Row, _
Northwind.ProductsRow)
db.OnClientClick = String.Format( _
"return confirm('Are you certain you want to delete the {0} product?');", _
product.ProductName.Replace("'", "\'"))
End If
End Sub
此事件处理程序处理数据行 (那些将具有“删除”按钮) ,并通过以编程方式引用“删除”按钮开始的数据行。 通常使用以下模式:
Dim obj As ButtonType = _
CType(e.Row.Cells(commandFieldIndex).Controls(controlIndex), ButtonType)
ButtonType 是 CommandField - Button、LinkButton 或 ImageButton 使用的按钮类型。 默认情况下,CommandField 使用 LinkButtons,但这可以通过 CommandField 进行 ButtonType property
自定义。 commandFieldIndex 是 GridView 集合中 CommandField 的Columns
序号索引,而 controlIndex 是 CommandField 集合中“删除”按钮的Controls
索引。 controlIndex 值取决于相对于 CommandField 中其他按钮的按钮位置。 例如,如果 CommandField 中显示的唯一按钮是“删除”按钮,请使用索引 0。 但是,如果“删除”按钮前面有一个“编辑”按钮,请使用索引 2。 使用索引 2 的原因是 CommandField 在“删除”按钮之前添加了两个控件:“编辑”按钮和用于在“编辑”和“删除”按钮之间添加一些空格的 LiteralControl。
对于我们的特定示例,CommandField 使用 LinkButtons,并且作为最左侧的字段, commandFieldIndex 为 0。 由于除了 CommandField 中的“删除”按钮之外没有其他按钮,因此我们使用 controlIndex 为 0。
在引用 CommandField 中的“删除”按钮后,我们接下来获取绑定到当前 GridView 行的产品的相关信息。 最后,将“删除”按钮的 OnClientClick
属性设置为相应的 JavaScript,其中包括产品名称。 由于传入函数的 confirm(string)
JavaScript 字符串是使用撇号分隔的,因此必须转义产品名称中显示的任何撇号。 具体而言,产品名称中的任何撇号都使用“”\'
进行转义。
完成这些更改后,单击 GridView 中的“删除”按钮将显示自定义的确认对话框, (请参阅图 4) 。 与 FormView 中的确认消息框一样,如果用户单击“取消”,则取消回发,从而防止删除。
注意
此方法还可用于以编程方式访问 DetailsView 中 CommandField 中的“删除”按钮。 但是,对于 DetailsView,需要为 DataBound
事件创建事件处理程序,因为 DetailsView 没有 RowDataBound
事件。
图 4:单击 GridView 的“删除”按钮显示自定义的确认对话框 (单击以查看全尺寸图像)
使用 TemplateFields
CommandField 的缺点之一是必须通过索引访问其按钮,并且生成的对象必须强制转换为相应的按钮类型 (Button、LinkButton 或 ImageButton) 。 使用“神奇数字”和硬编码类型会引发在运行时之前无法发现的问题。 例如,如果你或其他开发人员在将来的某个时间点向 CommandField 添加新按钮, (例如“编辑”按钮) 或更改 ButtonType
属性,则现有代码仍将进行编译,而不会出错,但访问页面可能会导致异常或意外行为,具体取决于代码的编写方式和所做的更改。
另一种方法是将 GridView 和 DetailsView 的 CommandFields 转换为 TemplateFields。 这将生成一个 TemplateField,其中包含 ItemTemplate
CommandField 中每个按钮的 LinkButton (或 Button 或 ImageButton) 。 这些按钮 OnClientClick
属性可以声明方式分配(正如我们在 FormView 中看到的),也可以使用以下模式在适当的 DataBound
事件处理程序中以编程方式访问:
Dim obj As ButtonType = CType(e.Row.FindControl("controlID"), ButtonType)
其中 ,controlID 是按钮属性 ID
的值。 虽然此模式仍需要强制转换的硬编码类型,但它不需要索引,从而允许更改布局而不导致运行时错误。
总结
JavaScript confirm(string)
函数是控制表单提交工作流的常用方法。 执行时,函数将显示一个模式客户端对话框,其中包含两个按钮:“确定”和“取消”。 如果用户单击“确定”,则 confirm(string)
函数返回 true
;单击“取消”将 false
返回 。 此功能加上浏览器在提交过程中的事件处理程序返回 false
时取消表单提交的行为,可用于在删除记录时显示确认消息框。
函数 confirm(string)
可以通过 控件 的 属性与 Button Web 控件的客户端 onclick
事件处理程序 OnClientClick
相关联。 在模板中使用“删除”按钮时(无论是在 FormView 的模板之一中,还是在 DetailsView 或 GridView 中的 TemplateField 中),都可以以声明方式或编程方式设置此属性,如本教程所示。
编程快乐!
关于作者
斯科特·米切尔是七本 ASP/ASP.NET 书籍的作者和 4GuysFromRolla.com 的创始人,自 1998 年以来一直在使用 Microsoft Web 技术。 Scott 担任独立顾问、培训师和作家。 他的最新一本书是 山姆斯在 24 小时内 ASP.NET 2.0。 可以在 上mitchell@4GuysFromRolla.com联系他,也可以通过他的博客(可在 中找到http://ScottOnWriting.NET)。