一、背景介绍
在一个工资管理的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所示。

图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所示。


五、编辑改动行的识别
现在的运行情况基本上能满足用户的需求,当在修改数据后,需要进行选择当前行的检查框;为了方便用户,当数据修改后让程序自动选择本行的数据,这样更能提高用户的效率。当然那种通过“回发方式”(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,稍加改动就能达到同样的效果。有兴趣的同行可以深入实践。
|