DELPHI與.Net

程序開發中......... [注明:该Blog中的信息都并非原创,只是作为个人的阅读笔记]

另类DATAGRID数据编辑修改

另类DATAGRID数据编辑修改
武汉 马建国
2003-8-28 13:43:00

 

基于数据库的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控件产生的数据显示页面:

点选考生代码"200306003"记录对应的 "编辑"超链后,页面将变为图2所示的编辑页面:

上述图例的实现是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运行界面:

"考试成绩"和"是否通过"两项与其它项一样正确地显示了初始取值,没有了Datagrid常见的编辑按钮后, 它们照样可以随时修改而且没有页面的重载刷新,修改后的数据保持在界面上可被继续修改,修改值的范围也被限制在DropDownList规定的范围内,不必担心可能的数据逻辑错误,界面的效果和可操作性也得到明显的改善。

三、保存修改事件的程序编写

界面设计好了,就只剩保存事件程序代码的编写,写代码时将依照这样的原理:对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数据源查询语句和事件响应代码的修改全部结束,三部分的修改相互配合互为关联,此时再运行就可以通过统一的"保存修改"按钮实现数据的编辑存储了。

开发工具:XP + ASP.NET Web Matrix

数据库环境:Oracle 9i

运行环境:2000 Server + Microsoft .NET Framework + .NET Framework Data Provider for Oracle

posted on 2006-07-18 15:54  人淡如菊  阅读(920)  评论(0编辑  收藏  举报

导航