基于数据库的ASP.NET设计,使得众多企业和个人将原有的C/S应用系统转移到B/S模式下,.NET开发环境里提供的众多控件使得数据库的绑定和数据操作简便易行,其中Datagrid控件就是最常用的一个,为能在数据显示WEB页内同时实现数据的修改,Datagrid控件还提供了内嵌的编辑处理按钮组和对应的事件响应,本文将讨论Datagrid里数据修改的技术,并提供一种更为有效的数据编辑方式。
数据示例如下:
SQL>SELECT * FROM MJG_TEMP IDNO CLASS NAME RESULT PASS ---------- ---------- ---------- ------ ---- 2003060001 语文 陈国强 优 T 2003060002 数学 李小亮 中 T 2003060003 几何 杨梅 良 T 2003060004 英语 刘勇 差 F 2003060005 物理 刘青山 良 T 2003060006 化学 吴永请 差 F
下图为利用Datagrid控件产生的数据显示页面:
![](http://www.ccw.com.cn/resources/AD03A50E-9B02-4DB6-81C2-F5E6AD6FBCCC/0828-7.gif)
点选考生代码"200306003"记录对应的 "编辑"超链后,页面将变为图2所示的编辑页面:
![](http://www.ccw.com.cn/resources/AD03A50E-9B02-4DB6-81C2-F5E6AD6FBCCC/0828-8.gif)
上述图例的实现是Datagrid的常见应用,但它有以下不足:1、不能提供批次整屏修改。修改哪条记录必须先按"编辑"钮进入该条记录的编辑状态,修改完毕还必须按对应的"更新"钮保存修改;2、记录进入修改状态后,原有内容被清空不利于修改时的参照;3、修改编辑框缺省为TEXTBOX控件,对输入的修改值难以进行有效性判断,几乎无法提供数据检查和限制的能力;4、页面重载刷新频率较高,浏览者有"晃眼"的感觉,也加大了服务器负荷。点击"更新"钮保存修改后,页面将进行刷新,显示新的数据结果等待下一轮修改,如果我们在此例中对考试成绩有排序,原本位于第三条记录的考试成绩若被修改,将使得刷新后它出现在别的位置,记录一多用户就会感到"晃眼"记录位置变换了,若再遇网络(服务器)忙,用户的修改将陷入频繁等待中;5、三个事件定义不可少。在本例中编辑按钮事件OnEditCommand、更新按钮事件OnUpdateCommand和取消按钮事件OnCancleCommand需要进行响应代码设计,Datagrid并没有自动地来完成。
如何克服这些缺陷?回到象C/S方式那样灵活稳定的操控界面?我们需要首先了解Datagrid工作的原理,上例的Datagrid页面描述代码如下:
<asp:DataGrid id="DataGrid1" runat="server" AutoGenerateColumns="False" OnEditCommand=……> …… <Columns> <asp:BoundColumn DataField="idno" ReadOnly="True" HeaderText="考生代码"> </asp:BoundColumn> <asp:BoundColumn DataField="name" ReadOnly="True" HeaderText="考生姓名"> </asp:BoundColumn> <asp:BoundColumn DataField="class" ReadOnly="True" HeaderText="考试课目"> </asp:BoundColumn> <asp:BoundColumn DataField="result" HeaderText="考试成绩"> </asp:BoundColumn> <asp:BoundColumn DataField="pass" HeaderText="是否通过"> </asp:BoundColumn> <asp:EditCommandColumn ButtonType="LinkButton" UpdateText="更新" HeaderText="修改" CancelText="取消" EditText="编辑"> </asp:EditCommandColumn> </Columns> </asp:DataGrid>
进行数据绑定的总共有五列,第六列为编辑按钮组。定义的前三列"考生代码"、"考生姓名"和"考试课目"都为"ReadOnly"属性,表示DataGrid处于编辑状态时,此三列不能被编辑,显示样式也不会发生变化;第四、五两列"考试成绩"与"通过与否"都是可编辑列,一旦DataGrid处于编辑状态,此两列就将由Label显示变为内定的TextBox编辑框,从而允许用户编辑。这种原理也就导致了DataGrid具有显示状态和编辑状态两种模式,页面在模式间切换时的刷新就不可避免,要想改变必须走"另类"的道路。因篇幅所限不详细介绍上例的事件代码。
我们将介绍的另类DataGrid编辑修改,将在以下方面进行改造:1、把允许编辑的第四、五两列由绑定列改变为模板列;2、将模板列的显示状态Label样式与编辑状态TextBox样式合并为兼具数据显示和修改功能的DropDownList或CheckBox等(TextBox本身也是显示、编辑兼具,但它缺少数据限制和自检的能力),利用这些控件的特性限制修改值的范围;3、取消第六列编辑按钮组及对应的事件,合并为界面上一个独立的按钮,该按钮的响应就是保存当前整屏修改后的数据。下面按步骤详细介绍。
一、绑定列变为模板列,同时取消第六列的按钮组,界面描述代码见下:
<asp:DataGrid id="DataGrid1" runat="server" AutoGenerateColumns="False"> ' 取消按钮组后,DataGrid自身已经没有事件响应的定义 …… <Columns> '开始定义列 <asp:BoundColumn DataField="idno" ReadOnly="True" HeaderText="考生代码"> <ItemStyle horizontalalign="Center"></ItemStyle> </asp:BoundColumn> <asp:BoundColumn DataField="name" ReadOnly="True" HeaderText="考生姓名"> <ItemStyle horizontalalign="Center"></ItemStyle> </asp:BoundColumn> <asp:BoundColumn DataField="class" ReadOnly="True" HeaderText="考试课目"> <ItemStyle horizontalalign="Center"></ItemStyle> </asp:BoundColumn> ' 前三列没有发生改变,仍然是BoundColumn(绑定列) <asp:TemplateColumn HeaderText="考试成绩"> ' 第四列定义开始 <ItemTemplate> <asp:Label runat="server" Text='<%# DataBinder.Eval(Container, "DataItem.result") %>'></asp:Label> </ItemTemplate> ' 第四列在显示模式的定义,仍使用了label <EditItemTemplate> <asp:TextBox runat="server" Text='<%# DataBinder.Eval(Container, "DataItem.result") %>'></asp:TextBox> ' 第四列在编辑模式时,其初始值取数据源当前记录的result字段 </EditItemTemplate> ' 第四列编辑模式的定义,仍使用了textbox </asp:TemplateColumn> ' 第四列改变为TemplateColumn(模板列), <asp:TemplateColumn HeaderText="是否通过"> '第五列定义开始 <ItemTemplate> <asp:Label runat="server" Text='<%# DataBinder.Eval(Container, "DataItem.pass") %>'></asp:Label> </ItemTemplate>' 第五列在显示模式的定义,仍使用了label <EditItemTemplate> <asp:TextBox runat="server" Text='<%# DataBinder.Eval(Container, "DataItem.pass") %>'></asp:TextBox> ' 第五列在编辑模式时,其初始值取数据源当前记录的pass字段 </EditItemTemplate> ' 第五列编辑模式的定义,仍使用了textbox </asp:TemplateColumn> </Columns> ' 列定义完毕 </asp:DataGrid>
二、合并显示模式与编辑模式
经过上面的调整,只完成了绑定列到模板列的转换,第四、五两列仍存在显示和编辑两种模式,下面将用DropDownList替换第四列、用CheckBox替换第五列的定义,描述代码如下:
…… <asp:TemplateColumn HeaderText="考试成绩"> ' 第四列定义开始 <ItemTemplate> <asp:DropDownList id="DropDownList1" runat="server" Width="60px" selectedindex='<%# DataBinder.Eval(Container, "DataItem.result") %>'> ' 第四列被定义为DropDownList项,该对象的ID指定为DropDownList1,它只有五种可选值 <asp:ListItem Value="优">优</asp:ListItem> <asp:ListItem Value="良">良</asp:ListItem> <asp:ListItem Value="中">中</asp:ListItem> <asp:ListItem Value="差">差</asp:ListItem> <asp:ListItem Value="无">无</asp:ListItem> </asp:DropDownList> </ItemTemplate> </asp:TemplateColumn> ' 第四列没有了编辑模式,只存在显示模式 <asp:TemplateColumn HeaderText="是否通过"> '第五列定义开始 <ItemTemplate> <asp:CheckBox id="CheckBox1" runat="server" text="通过" checked='<%# DataBinder.Eval(Container, "DataItem.pass") %>'></asp:checkbox> ' 第五列被定义为CheckBox项,该对象ID指定为CheckBox1,只有两种状态可选 </ItemTemplate> ' 第五列也没有了编辑模式,只有显示模式 </asp:TemplateColumn> </Columns> ' 列定义完毕 </asp:DataGrid>
大家会问第四列被替换为DropDownList后,其selectedindex属性动态绑定到当前记录的result字段,前者是数字型取值,后者是字符串值,二者如何赋值?同样还有第五列,CheckBox的布尔型逻辑值Checked怎么被赋为字符串值?实际上我们在取值的SQL语句上也需要做出修改,程序代码如下:
sub show_data ' 在浏览界面上显示数据的过程 dim sql as string dim mycomm As New OracleCommand() sql="select idno,class,name,decode(result,'优','0','良','1','中','2','差','3','4') as result,decode(pass,'T','true','false') as pass from mjg_temp" Dim myadapter As New OracleDataAdapter() myadapter.SelectCommand = new OracleCommand(sql,session("database")) 'session("database")为定义的数据库连接对象,以session变量的形式储存 dim mydataset as new dataset() myadapter.fill(mydataset,"mytable") datagrid1.datasource=mydataset.tables("mytable").defaultview datagrid1.databind ' 将datagrid1绑定给SQL语句查询到的结果数据集,产生显示 session("database").close() end sub
Sub Page_Load(sender As Object, e As EventArgs) ' 页面加载事件定义 if not ispostback then show_data end if End Sub 由于数据库后台使用Oracle平台,因此在Asp.Net程序代码里定义使用了相应的Oracle数据库操控对象;SQL语句里的Decode函数也是针对Oracle的查询函数,其作用是当result字段值为'优'、'良'、'中'、'差'时,分别将结果转换为'0'、'1'、'2'、'3',为其它值时转换为'4';当pass字段值为'T'时,将结果转换为'true',否则转换为'false'。通过这样的转换,DropDownList和CheckBox就可以绑定到正确的参数值上了。(其它数据库平台也有类似DECODE的函数,此处不详述)。经过上述修改,我们将看到下面的Asp.Net运行界面:
![](http://www.ccw.com.cn/resources/AD03A50E-9B02-4DB6-81C2-F5E6AD6FBCCC/0828-9.gif)
"考试成绩"和"是否通过"两项与其它项一样正确地显示了初始取值,没有了Datagrid常见的编辑按钮后, 它们照样可以随时修改而且没有页面的重载刷新,修改后的数据保持在界面上可被继续修改,修改值的范围也被限制在DropDownList规定的范围内,不必担心可能的数据逻辑错误,界面的效果和可操作性也得到明显的改善。
![](http://www.ccw.com.cn/resources/AD03A50E-9B02-4DB6-81C2-F5E6AD6FBCCC/0828-10.gif)
三、保存修改事件的程序编写
界面设计好了,就只剩保存事件程序代码的编写,写代码时将依照这样的原理:对Datagrid里的"考试成绩"和"是否通过"项进行逐行取值,将DropDownList的当前selectedindex数值转换为对应的字符串值,将CheckBox的当前Checked逻辑值转换为对应的字符串值'T'或'F',以考生代码为检索条件进行数据表的修改操作,程序代码如下
Sub SaveButton_Click(sender As Object, e As EventArgs) dim string_tem1 as string ' 定义字符串变量,用于存放考试成绩字符串值 dim string_tem2 as string ' 定义字符串变量,用于存放是否通过字符串值 Dim item As DataGridItem ' 定义DataGridItem对象,用于定位Datagrid里的每一行 dim mycontrol1 as Dropdownlist ' 定义Dropdownlist对象,用于定位Datagrid每行里的Dropdownlist dim mycontrol2 as CheckBox ' 定义Checkbox对象,用于定位Datagrid每行里的Checkbox dim mycomm As New OracleCommand() mycomm.Connection = session("database") session("database").open() For Each item In dataGrid1.Items ' 此循环在Datagrid里处理每一行 mycontrol1 = item.findcontrol("dropdownlist1") ' findcontrol是Datagrid的行对象Items的方法 select case mycontrol1.selectedindex case 0 string_tem1="优" case 1 string_tem1="良" case 2 string_tem1="中" case 3 string_tem1="差" case 4 string_tem1="无" end select ' Case判断用于将Dropdownlist的当前选择序号转换为对应的成绩字符串值 mycontrol2 = item.findcontrol("checkbox1") if mycontrol2.checked then string_tem2="T" else string_tem2="F" ' IF判断将checkbox的当前选择转换为对应的是否通过字符串T或F mycomm.Commandtext = "update mjg_temp set result='"+string_tem1+"',pass='"+string_tem2+"' where idno='"+item.cells(0).text+"'" ' item.cells(0)即Datagrid当前行的第一列,其text属性就是所显示的值,这里就是考生代码,保存修改将以此作为记录定位条件 mycomm.executereader() Next item session("database").close() show_data ' 保存修改完毕之后,再进行数据重新提取,用户浏览界面将重载刷新,子过程在上段代码中 End Sub
这里需要对为什么用FindControl函数进行一些说明:取Datagrid里某行某列的值,要先先定位行,指定Datagrid的Itemindex值后,Datagrid.items即为对应行,上例代码中因将遍历所有行,就没有指定Itemindex,当前行被赋给事先定义的item对象。item中包含多个列,取通常列的值,我们可使用Datagriditem对象的cells(i)属性,参数i为列号值,0代表第一列。当行中有特殊值(本例中就是第四列的Dropdownlist对象和第五列的Checkbox对象),就需要使用Datagriditem对象的Findcontrol方法,在当前行里查找指定ID的内嵌对象,找到后就可以引用它自身的属性和方法了。在本例中两对象的ID分别被指定为Dropdownlist1和Checkbox1(参见第三段代码)。
经过这番修改后,网页元件描述界面、SQL数据源查询语句和事件响应代码的修改全部结束,三部分的修改相互配合互为关联,此时再运行就可以通过统一的"保存修改"按钮实现数据的编辑存储了。
![](http://www.ccw.com.cn/resources/AD03A50E-9B02-4DB6-81C2-F5E6AD6FBCCC/0828-11.gif)
开发工具:XP + ASP.NET Web Matrix
数据库环境:Oracle 9i
运行环境:2000 Server + Microsoft .NET Framework + .NET Framework Data Provider for Oracle
|