张建 张萍
摘要 根据实际工作经验介绍如何使用DataGrid控件,实现表头固定,垂直和水平两个方向的滚动;如何加入文本编辑(TextBox)控件,检查框(CheckBox)控件;结合JavaScript在客户端实现对编辑改动内容行的自动识别。 关键词 DataGrid,Asp.NET1.x,Asp.NET2.0,JavaScript 一、背景介绍 在一个工资管理的Web项目中,需要对众多人员的工资数据进行编辑,每一个人员工资又包含多项数据,需要一个类似Excel表格方式的录入界面。 DataGrid虽然提供了数据的编辑功能,但只能进行一行数据的添加、修改、删除的编辑功能,限制了对大量数据的编辑,显然不能满足用户的需求,操作不便。通过深入研究,实现了对DataGrid的表头的固定,多行数据的编辑,数据修改能够自动识别,扩展了DataGrid的编辑能力,方便了用户的使用,提高编程效率。 二、实现表头的固定 关于DataGrid表头固定的技术在很多网站上都有介绍,笔者采用了www.codeproject.com网站上的一篇文章提到的一个控件(文章的地URL为:http://www.codeproject.com/aspnet/ScrollingGrid.asp),大家可以参考上面的文章。网站上的控件为Asp.NET1.1版本的,经过本人的升级,加入了一些实用的属性,现在可以使用在Asp.Net2.0的版本中。在附带的源代码中有本控件的.NET2.0版本的升级程序。 1.本控件的优点 支持多种浏览器:Mozilla Firefox 1+, Internet Explorer 5+, Netscape 7+;支持<select>元素的正确的显示;支持页面提交后,表格控件能自动定位到原先的位置;完全支持ASP.NET DataGrid ,并且支持用户在Visual Studio 可视化编辑环境中的编辑模式;使用简单,支持一个页面上的多个表格。 2.缺点 仅仅支持表头的固定,不支持列方式的固定方式,且需要JavaScript的支持。 3.具体的使用指导 经过实践,发现本控件使用方法简单,同时又不影响DataGrid控件的正常使用,适用于Asp.NET1.1和Asp.NET2.0的环境(升级后的控件),便于升级以前的Asp.NET1.X方式下的应用程序。现在本控件已经成功地应用在“Web化的工资管理软件系统”中。本控件的应用为编程带来了很多方便。控件的基本使用步骤如下: (1) 下载相应的DLL文件包,解压到Web项目的根目录中。文件如下: bin/ScrollingGrid.dll ScrollingGrid.js (2) 通过浏览方式把 ScrollingGrid 控件(bin/ScrollingGrid.dll)添加到 toolbox 中。 (3) 在你的页面上添加一个 ScrollingGrid 控件。 (4) 把一个 DataGrid 拖进 ScrollingGrid 控件中。 如果页面不是在Web项目的根目录下面,需要设置ScrollingGrid 控件的ScriptPath属性,使它指向相应的ScrollingGrid.js所在的目录。 如: ScriptPath="../"。 大家也可以利用HTML接加入本控件,具体方法可以参考原文章页面。 三、利用模板加入其他编辑控件 DataGrid控件的好处在于它支持Asp.NET1.0-2.0,并且性能在升级过程中逐渐得到提高,兼容Asp.NET的各个版本。当然也可以采用微软新推出的版本GridView新控件来替代DataGrid控件,它们之间有很多相似之处。为了加入其他编辑控件,需要利用DataGrid支持的模板列(TemplateColumn)的特性,利用它,可以按照指定的模板显示列中的各项,就可以在列中加入自定义控件。可以根据需要加入检查框控件,编辑框控件,列表框控件等众多控件,本例中只是添加了检查框和列表框的控件。 四、建立一个Web应用程序 为了展示上面介绍的内容,同时为了方便后面的内容的介绍,现在通过VS2005建立一个Web应用程序,应用名称为EditDatagrid,应用程序的主要目录设置如图1所示:

图1 应用程序目录结构图 1.文件介绍 persondb.mdb:用到的样例数据库文件;scrollgrid.dll,scrollinggrid.js:表头固定控件的相关文件;css.css:web页面用到的层叠样式表文件;select.js:后文介绍的重要脚本文件;default.aspx:页面文件。 2.页面文件介绍 首先按照上文介绍的方法,加入一个ScrollGrid控件和一个DataGrid控件;然后加入如图2所示的其他控件;在页面中加入对样式表文件的引用。图2所示的页面只是实际应用页面精简后的实验页面,剔除了很多无用的控件。最终的设计页面显示如下:

图2 工资录入界面 “修改”按钮是向数据库提取相应的数据 ,用于进行对数据进行修改。“提交”按钮是把修改的数据提交到数据库中,根据选择,保存提交的结果。“删除”按钮是把选定的数据行删除。 3.模板列的使用 由于采用了模板列,我们可以轻松实现对多行数据的编辑。加入了检查框控件的目的是实现对选择的数据的修改,包括删除。关于模板列的加入方法,可以查看下面的源代码。从三个部分分别讲解: 实现检查框的加入,代码如下: <asp:TemplateColumn HeaderText="选择"> <ItemStyle Width="5%"></ItemStyle> <ItemTemplate> <asp:CheckBox ID="CheckBox1" runat="server" Text=" "> </asp:CheckBox> </ItemTemplate> </asp:TemplateColumn> 为了实现对当前行的标记,需要提取数据库记录的一个关键值,在本例中把人员的“身份证”(card)信息作为隐藏部分提取出来(这是一个小技巧),保存在页面之中,核心代码如下: <asp:TemplateColumn HeaderText="姓名"> <ItemStyle Width="15%"></ItemStyle> <ItemTemplate> <asp:Label Text='<%# DataBinder.Eval(Container.DataItem,"name") %>' runat="server" ID="Label4" /> <asp:Label Visible='False' Text= '<%# DataBinder.Eval(Container.DataItem,"card") %>' runat="server" ID="Label5" /> </ItemTemplate> </asp:TemplateColumn> 加入编辑框,下面是其中的一个例子列(“加班费”列),代码如下: <asp:TemplateColumn HeaderText="加班"> <ItemStyle Width="10%"></ItemStyle> <ItemTemplate> <asp:TextBox Text='<%# DataBinder.Eval(Container.DataItem,"p17") %>' runat="server" ID="TBjb" Width="80px" /> </ItemTemplate> </asp:TemplateColumn> 4.程序现在的运行效果 完成上面的界面后,在后台加入数据库的提取代码,以及修改和删除的代码,呈现给用户的界面如图3所示:

图3 程序现在的运行效果 五、编辑改动行的识别 现在的运行情况基本上能满足用户的需求,当我们在修改数据后,但需要进行选择当前行的检查框;为了方便用户,当数据修改后让程序自动选择本行的数据,这样更能提高用户的效率。当然那种通过“回发方式”(postback)实现的这样的功能并不可取,因为数据每次修改,都要同服务器进行通讯,既影响速度,又不方便用户的数据的输入。下面利用客户端的JavaScript进行数据操作,实现上面的功能,速度快、用户效率高并且用户界面友好。 1.DataGrid产生的HTML的代码分析 为了设计通用的客户端的脚本语言,首先需要对DataGrid产生的代码进行分析,总结规律,然后着手客户端的代码的编写。

图4 表格中的第一行的部分HTML语言代码

图5 表格中的第二行的HTML语言代码 由图4、图5可以总结出来的规律是,当模板列里面的控件呈现时(Render),相应的控件的ID或者NAME的标记同“DataGrid的ID”,“相应的行数”和“当前控件的ID”有关,示例中的DataGrid的ID为“Pub”,检查框的ID为CheckBox1,一个文本框的ID为TBjb。可见当前行的所有控件的ID只是后面的部分不一样,前面的部分相同。如第一行的控件相应的ID值为Pubs_ctl02_CheckBox1和Pubs_ctl02_TBjb,而且后面的部分就是编程时的“控件ID”。通过以上部分的分析,为实现自动识别数据改动的客户端代码的提供了必要支持。 2.编写通用的脚本文件 通用脚本文件的代码如下: // JScript 文件 //适用于ie,通过Id实现数据的选择, //当录入数据发生变化后,Checkbox进行选择 //Checkbox的名称后缀为pcname //tt为文本输入框对象 function checkThisBy_Id(tt,pcname) { //document.forms[0]['Pubs__ctl3_Checkbox2'].checked //=!document.forms[0]['Pubs__ctl3_Checkbox2'].checked; //alert(tt.id+"--"+tt.type); var tname=tt.id; var index=tname.lastIndexOf("_"); //在限定的表格内 if(index>0) { var ptname=tname.substring(index+1); //checkbox名称 var cname=tname.replace(ptname,pcname); var checkbox=document.getElementById(cname); //checkbox.checked=!checkbox.checked; checkbox.checked=true; } }
//自动添加事件 //指定form, 表格控件pgrid,在子控件的名字中包含相应的名字子字符串 //需要选中的控件的(名字)标记 function addTextSelect(frm,pgrid) { //frm=eval(sfrm); //alert("--hello"); var trk=0; var index=-1; if(frm!=null) { for (var i=0;i<frm.elements.length;i++) { var e=frm.elements[i]; index=e.name.indexOf(pgrid); if((e.type=='text') && index>=0) { e.onchange=function(){checkThisBy_Id(this,'CBxz')}; } } } } 为了看懂上面的内容的含义,需要研究一下JavaScript语言,这些不是本文需要讲述的关键。其功能就是实现对一个表格内的一行数据的修改(文本框控件的内容改动)触发客户端事件,自动选择检查框。具体的过程,在注视行中进行了解释。设计完成这个脚本文件Select.js,就可以进行下面的工作,首先把脚本文件引入到我们的页面文件中,接着当表格呈现完成后,执行相应的脚本,实现客户端时间的添加,这是下面要执行的任务。 3.脚本函数的执行 当表格数据重新绑定后,都要执行相应的脚本函数,用于实现客户端事件的添加,在VS2005中,为编程人员提供了一个很好的函数进行实现,下面实现的核心代码: //提取数据的过程,对应于“修改”按钮 Protected void Button1_Click2(objectsender,EventArgse) { //为DataGrid提供数据 bindsql(); //为当前表格内的所有文本框加上修改后触发事件 AddAutoSelect(Pubs); } ///<summary> ///在表格呈现后调用脚本文件的过程 ///</summary> ///<paramname="dg"></param> Public void AddAutoSelect(DataGriddg) { stringdgid=dg.ID; stringstrScript="setTimeout (\"addTextSelect(document.forms[0], '"+dgid+"')\",250)"; ClientScript.RegisterClientScriptBlock (this.GetType(), "AddTextSelect",strScript,true); } 值得注意的是,在AddAutoSelect过程中,通过ClientScript.RegisterClientScriptBlock函数的调用,实现了脚本函数的调用,是本节的难点所在。 4.数据的识别和提交 如何实现对表格的各行数据的遍历是当前工作的最后一个难点。为了提交数据,我们必须要执行的任务就是遍历表格的每一行数据,并且提取相应的各个控件的数据项,相应的代码如下:
for (int i = 0; i < this.Pubs.Items.Count; i++) { //遍历表格的各个行开始 CheckBox ctrcheck = (CheckBox)Pubs.Items[i].FindControl("CheckBox1");//选择框 if (ctrcheck.Checked) { Label ctrname = (Label)Pubs.Items[i].FindControl("Label4");// Label ctrcard = (Label)Pubs.Items[i].FindControl("Label5"); TextBox ctrpnjb = (TextBox)Pubs.Items[i].FindControl("TBjb");//加班 TextBox ctrpnyb = (TextBox)Pubs.Items[i].FindControl("TByb");//夜班 TextBox ctrpnyj = (TextBox)Pubs.Items[i].FindControl("TByj");//绩效 TextBox ctrpnwc = (TextBox)Pubs.Items[i].FindControl("TBwc");//补助 TextBox ctrpnhd = (TextBox)Pubs.Items[i].FindControl("TBhd");//津贴 pinname = ctrname.Text.Trim(); pincard = ctrcard.Text.Trim(); //加班 if (ctrpnjb.Text.Trim() == String.Empty) pn5 = 0; else pn5 = Decimal.Parse(ctrpnjb.Text); //夜班 if (ctrpnyb.Text.Trim() == String.Empty) pn6 = 0; else pn6 = Decimal.Parse(ctrpnyb.Text); //业绩奖励 if (ctrpnyj.Text.Trim() == String.Empty) pn1 = 0; else pn1 = Decimal.Parse(ctrpnyj.Text); pn2 = 0;
//补助 if (ctrpnwc.Text.Trim() == String.Empty) pn8 = 0; else pn8 = Decimal.Parse(ctrpnwc.Text); //津贴 if (ctrpnhd.Text.Trim() == String.Empty) pn7 = 0; else pn7 = Decimal.Parse(ctrpnhd.Text); //实现数据的提交 if (AddorReplaceRsgz02(rq1, pincard, pinname, pn1, pn2, pn3, pn4, pn5, pn6, pn7, pn8, 1)) { this.state1.Text = "成功提交"; } else { this.state1.Text = "提交失败"; } } }
六、运行效果 通过上面技术应用,实现了表格的多行编辑功能,同时为每行的编辑提供了修改后自动选择的功能,为用户的批量数据的修改提供了方便,最后效果如图6所示:

图6 运行效果图
上面的内容是为了兼容Asp.Net1.x,根据DataGrid进行了讲解,随着Asp.NET2.0的推出,又推出了一个新的控件GridView,它同DataGrid有很多相似的地方,上面文章中所讲到的技术同样适用于GridView,稍加改动就能达到同样的效果。有兴趣的同行可以深入实践。
参考文献: 1 Ashley van Gerven.http://www.codeproject.com/aspnet/ScrollingGrid.asp. 2 Dave Crane.Eric Pascarello.AJAX实战.
|