Scott Mitchell 的ASP.NET 2.0数据教程之二十二:为删除数据添加客户端确认-程序员宅基地

技术标签: ViewUI  人工智能  数据库  javascript  

导言

在前面一些教程中,我们已经看到如何使用应用程序框架,ObjectDataSource,以及那些提供增、改、删功能的数据Web控件。在我们已经实现的删除数据的界面中,包含一个删除按钮,当点击它的时候,会导致数据回传以及调用ObjectDataSource的Delete()方法。然后Delete()方法会调用对应业务逻辑层中的方法,再进入数据访问层,直至调用最终操作数据库的DELETE语句。

虽然这个界面已经能够让用户通过GridView,DetailsView,或者FormView控件来删除记录,但是在用户点击删除按钮的时候,它缺少一些提示信息。如果用户本想点击编辑按钮,但是不小心点击了删除按钮,那么原本会更新的记录将会被删除。为了避免此类事情发生,在这篇教程里面,我们将为点击删除按钮的时候,添加一个能在客户端显示提醒的窗口。

JavaScript的confirm(string)方法将在一个模式窗口中显示那些作为string参数传进来的文本,这个窗口将会显示两个按钮-确定(OK)和取消(Cancel)。(见图1)confirm(string)方法将根据点击不同的按钮来返回一个布尔类型值。(返回true,如果点击了确定(OK),返回false如果点击了取消(Cancel))

 

图1:JavaScript的confirm(string)方法显示一个模式的,客户端的窗口

在一个表单的提交过程中,如果从客户端的事件处理器返回一个false值,那么这个表单将取消提交。使用这种特性,我们可以在这个删除按钮的客户端事件处理器 onClick中,调用confirm(“你确定要删除这个产品吗?”),让它返回一个布尔值。如果用户点击了取消,confirm(string)将返回false,因此会取消表单的提交。在没有回传的前提下,这个已经点击了删除按钮的产品并没有被删除。相反,如果在确认窗口中用户点击了确定,回传将会继续而且这个产品将会被删除。参考 使用JavaScript的confirm()方法控制表单提交 来获取这方面的更多信息。

在添加这些有用的客户端脚本时候,使用模版和使用一个CommandField相比,将会有一些细微的差别。因此,在这篇教程中,我们将同时考察FormView和GridView的例子。

注意:正如这篇教程中讨论到的,使用客户端确认技术时候,我们假设用户的浏览器支持JavaScript并且已经启用了JavaScript支持。如果这其中的任何一个假设不能满足,那么点击删除按钮的时候将会立即进行回传而不会显示一个确认窗口。

 

第一步:新建一个支持删除的FormView

首先在EditInsertDelete目录下面,创建ConfirmationOnDelete.aspx页面,并添加一个FormView控件,然后给这个控件绑定一个ObjectDataSource,这个数据源控件将从ProductsBLL类的GetProducts()方法获取产品信息。同时给它的Delete()方法绑定指向ProductsBLL类的DeleteProduct(productID)方法。确保INSERT和UPDATE标签的下拉框中为(None)。最后,在FormView的属性窗口中勾上Enable Paging多选框。

通过这些步骤,创建了一个以下语句声明的ObjectDataSource:

 1 None.gif < asp:ObjectDataSource ID = " ObjectDataSource1 "  runat = " server "  DeleteMethod = " DeleteProduct "
 2 None.gif
 3 None.gif    OldValuesParameterFormatString = " original_{0} "  SelectMethod = " GetProducts "  TypeName = " ProductsBLL " >
 4 None.gif
 5 None.gif     < DeleteParameters >
 6 None.gif
 7 None.gif         < asp:Parameter Name = " productID "  Type = " Int32 "   />
 8 None.gif
 9 None.gif     </ DeleteParameters >
10 None.gif
11 None.gif </ asp:ObjectDataSource >
12 None.gif


因为在我们前面的例子中没有使用到optimistic concurrency,可以把OldValuesParameterFormatString属性删掉。

因为这个FormView已经被绑定到一个仅仅支持删除的ObjectDataSource控件,在ItemTemplate中我们只要提供删除按钮,而不需要新建和更新按钮。而在FormView的声明标记中,可以删掉我们不再需要的EditItemTemplate以及InsertItemTemplate。稍微花点时间定制一下ItemTemplate以便只显示一组产品属性。我已经定制好了,用<h3>样式显示产品的名字作为标题,接下来是供应商和分类的名字(以及删除按钮)。

 1 None.gif < asp:FormView ID = " FormView1 "  runat = " server "  AllowPaging = " True "  DataKeyNames = " ProductID "
 2 None.gif
 3 None.gif    DataSourceID = " ObjectDataSource1 "  EnableViewState = " False " >             
 4 None.gif
 5 None.gif     < ItemTemplate >                 
 6 None.gif
 7 None.gif         < h3 >< i ><% # Eval( " ProductName " %></ i ></ h3 >
 8 None.gif
 9 None.gif         < b > Category: </ b >
10 None.gif
11 None.gif         < asp:Label ID = " CategoryNameLabel "  runat = " server "  Text = ' <%# Eval("CategoryName") %> ' >
12 None.gif
13 None.gif         </ asp:Label >< br  />
14 None.gif
15 None.gif         < b > Supplier: </ b >
16 None.gif
17 None.gif         < asp:Label ID = " SupplierNameLabel "  runat = " server "  Text = ' <%# Eval("SupplierName") %> ' >
18 None.gif
19 None.gif         </ asp:Label >< br  />
20 None.gif
21 None.gif         < asp:LinkButton ID = " DeleteButton "  runat = " server "  CausesValidation = " False "  CommandName = " Delete "
22 None.gif
23 None.gif            Text = " Delete " >
24 None.gif
25 None.gif         </ asp:LinkButton >
26 None.gif
27 None.gif     </ ItemTemplate >
28 None.gif
29 None.gif </ asp:FormView >
30 None.gif
31 None.gif


做了这些变化之后,我们已经有了一个功能完善的页面,可以允许用户显示每个产品,以及通过简单地点击按钮来删除某个产品。图2显示了在浏览器中访问我们上面所完成的例子的截图。

 

图2:FormView控件显示一个产品

 

第二步:在删除按钮的客户端onclick事件中调用confirm(string)方法

 在创建FormView之后,最后的步骤是配置这个删除按钮,使得用户点击它的时候,JavaScript的confirm(string)方法会被调用。可以通过使用OnClientClick这个属性来为Button,LinkButton,ImageButton的客户端onclick事件添加客户端脚本,这个属性是ASP.NET 2.0新引入的。因为我们想让confirm(string)方法有返回值,可以简单地设置属性值为:return confirm(‘你确定要删除这个产品吗?’)。

修改之后这个删除按钮的声明语法应该如下所述:

None.gif < asp:LinkButton ID = " DeleteButton "  runat = " server "  CausesValidation = " False "  CommandName = " Delete "  Text = " Delete "  OnClientClick = " return confirm('Are you certain that you want to delete this product?'); " >
None.gif
None.gif
</ asp:LinkButton >
None.gif


仅仅只需要这么多!图3给出了这个提示操作的截图。点击这个删除按钮激活确认窗口的显示。如果用户选择取消,回传将被取消,产品也不会被删除。相反,用户选择确定,回传继续,ObjectDataSource的Delete()方法被调用,最后数据库中相应的记录也会被删除。

注意:
传入confirm(string) JavaScript方法的字符串用单引号进行标记(而不是双引号)。在JavaScript中,标记字符串可以是单引号也可以是双引号。我们这里使用单引号是为了确保不影响OnClientClick这个属性本身的双引号标记。

 

图3:当点击删除按钮时候显示一个确认窗口

 

第三步:在一个CommandField中为删除按钮设置OnClientClick属性

 在模板中直接使用Button,LinkButton,或者ImageButton的时候,可以直接为它的OnClientClick属性设置确认窗口并返回confirm(string) JavaScript的返回值。然而,CommandField是在GridView或者DetailsView上内置的一些删除按钮,而且它们本身不具有OnClientClick属性可以设置声明。相反,我们必须要在处理GridView或者DetailsView,它们适当的DataBound事件的代码中,引用这个删除按钮,然后在那里设置它的OnClientClick属性。

 注意:
当我们在适当的DataBound事件处理器中设置删除按钮的OnClientClick属性时候,我们已经有权限访问当前绑定的数据。这意味着我们可以扩展确认信息,并包含具体记录的详细信息,比如,“你确定要删除这个Chai产品吗?“这些定制也可以在模板的数据绑定的语法中实现。

 为了实践在一个CommandField中设置删除按钮的OnClientClick属性,我们在页面上添加一个GridView。配置这个GridView使用FormView一样的ObjectDataSource控件。同时,限制GridView的BoundFields属性只包括产品名称,分类和供应商。最后,在GridView的属性窗口中勾上Enable Deleting的多选框。这样会在GridView的ColumnCollection的集合中添加一列CommandField,并且它的ShowDeleteButton属性会设置成true。

 做了这些改变后,你的GridView的声明标记应该如下所示:

 1 None.gif < asp:GridView ID = " GridView1 "  runat = " server "  AutoGenerateColumns = " False "  DataKeyNames = " ProductID "
 2 None.gif
 3 None.gif    DataSourceID = " ObjectDataSource1 "  EnableViewState = " False " >
 4 None.gif
 5 None.gif     < Columns >
 6 None.gif
 7 None.gif         < asp:CommandField ShowDeleteButton = " True "   />
 8 None.gif
 9 None.gif         < asp:BoundField DataField = " ProductName "  HeaderText = " Product "  SortExpression = " ProductName "   />
10 None.gif
11 None.gif         < asp:BoundField DataField = " CategoryName "  HeaderText = " Category "  ReadOnly = " True "  SortExpression = " CategoryName "   />
12 None.gif
13 None.gif         < asp:BoundField DataField = " SupplierName "  HeaderText = " Supplier "  ReadOnly = " True "  SortExpression = " SupplierName "   />
14 None.gif
15 None.gif     </ Columns >
16 None.gif
17 None.gif </ asp:GridView >
18 None.gif

 
这个CommandField包含一个删除LinkButton实例,并且可以在GridView的RowDataBound事件处理器中被访问。一旦被引用,我们就可以相应地设置它的OnClientClick属性。通过下面的代码来新建一个RowDataBound事件的处理器:

None.gif protected   void  GridView1_RowDataBound( object  sender, GridViewRowEventArgs e)
None.gif
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif
InBlock.gif    
if (e.Row.RowType == DataControlRowType.DataRow)
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif
InBlock.gif        
// reference the Delete LinkButton
InBlock.gif

InBlock.gif        LinkButton db 
= (LinkButton)e.Row.Cells[0].Controls[0];
InBlock.gif
InBlock.gif 
InBlock.gif
InBlock.gif        
// Get information about the product bound to the row
InBlock.gif

InBlock.gif        Northwind.ProductsRow product 
= (Northwind.ProductsRow) ((System.Data.DataRowView) e.Row.DataItem).Row;
InBlock.gif
InBlock.gif 
InBlock.gif
InBlock.gif        db.OnClientClick 
= string.Format("return confirm('Are you certain you want to delete the {0} product?');"
InBlock.gif
InBlock.gif        product.ProductName.Replace(
"'"@"\'"));
InBlock.gif
ExpandedSubBlockEnd.gif    }

InBlock.gif
ExpandedBlockEnd.gif}

None.gif
None.gif

 

这个事件处理器将在代码中绑定数据和引用删除按钮的时候被调用。总的来说,使用了以下模式:

None.gif ButtonType obj  =  (ButtonType) e.Row.Cells[commandFieldIndex].Controls[controlIndex];


ButtonType是被CommandField使用的一种按钮类型,可以是Button,LinkButton,或者ImageButton。默认情况下,CommandField使用LinkButton,但也可以通过CommandField的ButtonType属性来定制。CommandFieldIndex是CommandField在GridView中Columns集合中的原始索引,而controlIndex是删除按钮在CommandField的Controls集合中的索引。controlIndex的值由按钮在CommandField中和其他按钮的相对位置决定。例如,如果在CommandField中只有一个删除按钮,那么它的索引就是0。然而,如果在删除按钮前面还有一个编辑按钮,那么索引值是2。因为在删除按钮前面有两个控件,一个是编辑按钮,另一个是LiteralControl,用来隔离编辑按钮和删除按钮。

 在我们的例子中,CommandField使用了LinkButton,在最左端,commandFieldIndex的值是0。因为除了删除按钮,没有其他控件,所以controlIndex的值也为0。

 在引用了CommandField中的删除按钮之后,我们接下来可以获得GridView当前数据列的一些产品信息。最后,我们为删除按钮设置了OnClientClick属性的JavaScript值,其中包含了产品的名称。因为我们用单引号标记了传入confirm(string)的字符串参数,对于产品的名称我们必须要过滤可能出现在其中的单引号。具体来说,我们可以把产品名称中含有的单引号转义成,“\’“。

 做完这些改变之后,点击GridView中的删除按钮,可以显示一个定制后的确认信息(见图4)。如果用户点击弹出的确认窗口中的取消,回传将会被取消,从而阻止了删除操作发生。

 注意:
我们同样可以在代码中对DetailsView的CommandField使用这种技术。然而对于DetailsView,你需要为DataBound事件提供一个处理器,因为它没有RowDataBound事件。

 

图4:点击GridView的删除按钮,显示一个定制的确认信息窗口

 

使用TemplateFields

 使用CommandField的一个缺点是必须通过索引访问到它的按钮,这会导致对象被转换成对应的按钮类型(Button,LinkButton或者ImageButton)。使用“magic numbers“和硬编码的类型会导致只有在运行时候才会被发现的错误。例如,如果你,或者其他开发人员,在将来某个时候为CommandFields添加了新的按钮(比如是编辑按钮)或者改变了ButtonType属性,现有的代码将会顺利被编译,但是当页面访问时候就可能会抛出异常或者不可预料的错误,这些直接由你书写的代码和做的改变来决定。

 一个二者择一的办法是,不使用GridView或者DetailsView的CommandFields,而是使用TemplateFields。在TemplateField中可以含有ItemTemplate,在ItemTemplate下面可以设置LinkButton或者Button,ImageButton正如CommandField中的一样。而且这些按钮的OnClientClick属性是可以显示声明的,就像FormView中看到的,或者我们可以使用以下模式在代码中适当的DataBound事件处理器中访问,

None.gif ButtonType obj  =  (ButtonType) e.Row.FindControl( " controlID " );

 
controlID是按钮ID的属性值,虽然这种办法仍然需要硬编码类型的转换,但是不再需要索引,可以改变界面而不再出现运行错误。

总结

JavaScript的confirm(stirng)方法在表单递交过程中是一个经常使用的技术。当执行的时候,这个方法会显示一个模式的,客户端的窗口,包含两个按钮,一个OK(确定)一个Cancel(取消)。如果用户点击了OK(确定),confirm(string)方法会返回true,否则返回false。这种功能,以及在表单递交的事件处理器中返回false会导致浏览器取消表单提交的功能,可以用来在删除一条记录的时候的显示一个确认窗口。

 通过设置按钮控件的OnClientClick属性,可以使得这个confirm(string)方法和按钮控件的客户端onclick事件处理器相结合。当在模版中使用删除按钮的时候-或者在一个FormView的模版中,又或者一个TemplateField在DetailsView或GridView中-正如我们在教程中看到的一样,我们可以显示声明访问它或者在代码中访问它。

祝编程快乐!

 作者简介

 Scott Mitchell,著有六本ASP/ASP.NET方面的书,是4GuysFromRolla.com的创始人,自1998年以来一直应用 微软Web技术。Scott是个独立的技术咨询顾问,培训师,作家,最近完成了将由Sams出版社出版的新作,24小时内精通ASP.NET 2.0。他的联系电邮为[email protected],也可以通过他的博客http://ScottOnWriting.NET与他联系。

 

转载于:https://www.cnblogs.com/xiongeee/archive/2006/08/18/480043.html

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/akpaul6677/article/details/102347592

智能推荐

AES 加密解密方法_system.security.cryptography.aes 解密-程序员宅基地

using System;using System.Collections.Generic;using System.Linq;using System.Security.Cryptography;using System.Text;using System.Threading.Tasks;namespace fileEncrypt{ class Encrypt {..._system.security.cryptography.aes 解密

Java IO流学习总结六:ByteArrayInputStream、ByteArrayOutputStream-程序员宅基地

转自:http://blog.csdn.net/zhaoyanjun6/article/details/54946762本文出自【赵彦军的博客】类的继承关系InputStream|__ ByteArrayInputStreamOutputStream|__ ByteArrayOutputStreamByteArrayInputStream 可以将字节数组转化为输入流 。ByteArrayOutputStream可以捕获内存缓冲区的数据,转换成字节数组。ByteArrayInputS.

AMBA总线协议AHB、APB、AXI对比分析-程序员宅基地

一、AMBA概述&nbsp; &nbsp; AMBA (Advanced Microcontroller Bus Architecture) 高级处理器总线架构&nbsp; &nbsp; AHB (Advanced High-performance Bus) 高级高性能总线&nbsp; &nbsp; ASB (Advanced Sys...

今天安装的Ubuntu,我的开源第一步啊!-程序员宅基地

今天安装的Ubuntu,我的开源第一步啊!呵呵,不过比较纠结的是把Y450自带的一键还原搞坏了。。呵呵不过别的还好。嗯,加油!下一步要好好学习QT!哈哈哈!Go fighting!o(∩_∩)o 哈哈

Maven入门笔记_pom mirror_Mr. Wanderer的博客-程序员宅基地

文章目录Maven简介下载和安装下载安装配置Maven目录结构Maven项目目录结构手动创建Maven项目开发工具IDEA创建Maven项目Maven配置文件之settings.xml文件mirrorslocalRepository暂时不需要掌握的标签Maven仓库Maven项目的pom.xml文件Maven项目依赖Maven插件Maven之archetypeMaven聚合项目Maven插件之tomcat使用使用本地安装的tomcatmaven插件形式的tomcatMaven简介Maven官网:http_pom mirror

SVN 小乌龟(TortoiseSVN)本地文件更新报错Another process is blocking the working copy database 解决方法-程序员宅基地

在工作中使用小乌龟更新代码,报以下错误Error:svn: E200033: Another process is blocking the working copy database, or the underlying filesystem does not support file locking; if the working copy is on a network filesystem, make sure file locking has been enabled on the file _another process is blocking the working copy database, or the underlying fil

随便推点

mysql--->innodb引擎什么时候表锁什么时候行锁?-程序员宅基地

mysql innodb引擎什么时候表锁什么时候行锁?InnoDB基于索引的行锁InnoDB行锁是通过索引上的索引项来实现的,这一点MySQL与Oracle不同,后者是通过在数据中对相应数据行加锁来实现的。InnoDB这种行锁实现特点意味者:只有通过索引条件检索数据,InnoDB才会使用行级锁,否则,InnoDB将使用表锁在MySQL中,行级锁并不是直接锁记录,而是锁索引。索引分为主键索引..._什么时候行锁 什么时候表锁 innodb

python递归函数讲解_Python系列教程(二十四):递归函数-程序员宅基地

一、递归函数1、什么是递归函数函数体内可以调用其他函数,既然这样,那么可不可以函数自己调用自己呢?答案是可以的,函数通过直接或者间接调用自身,就是递归函数(Recursion)。2、使用递归函数的条件① 递归函数一定要有边界条件跟我们的循环有点类似,必须要有退出条件,不然就是死循环,而递归要是没有退出条件,就是无限递归,像上面那个图一样,走进了无尽深渊,永远出不来。② 递归的深度也不宜过深因为很消..._python递归函数详解

Mac下使用IDEA打包JavaFx的dmg安装包报错_idea打包dmg-程序员宅基地

Information:14/11/2017, 13:41 - Compilation completed with 3 errors and 0 warnings in 20s 385msError:Java FX Packager: BUILD FAILED/Users/xupanpan/Library/Caches/IntelliJIdea2017.3/compile-server/r_idea打包dmg

Flask项目之手机端租房网站的实战开发(十二)_移动端+flask演示-程序员宅基地

说明:该篇博客是博主一字一码编写的,实属不易,请尊重原创,谢谢大家!接着上一篇博客继续往下写 :https://blog.csdn.net/qq_41782425/article/details/86580344目录一丶房源列表页后端编写二丶房源列表页缓存处理三丶redis中pipeline(管道)的使用四丶房源列表页前端编写五丶搜索条件测试一丶房源列表页后端..._移动端+flask演示

C/C++调用Golang 二_c++ 调用go-程序员宅基地

《C/C++调用Golang 一》简单介绍了C/C++调用Golang的方法步骤,只涉及一个简单的函数调用。本文总结具体项目中的使用场景,将介绍三种较复杂的调用方式:一,C++向golang传入复杂结构体;二,C++向golang传入回调函数,在golang中调用C++函数;三,C++调用golang函数,返回复杂的结构体。(本文后面涉及三个例子,省略了编译步骤,仅展示关键代码。具体操作步骤参_c++ 调用go

python 读取PDF表格_pandas读取pdf-程序员宅基地

python读取PDF表格1.相关库函数利用python读取pdf中的表格部分,并且以EXCEL的形式保存到本地,主要利用了两个库,pdfplumber和pandas,前者用于操作PDF,后者用于操作EXCEL。先附上相关代码:import pdfplumberimport pandas as pddef pdf_read(): pdf = pdfplumber.open("aaaa.pdf") #pages=input("转换表格的页码") p0=pdf.pages[3_pandas读取pdf