1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > 自学Web开发第十四天-基于VB和ASP.NET;丰富数据呈现:TreeView控件的使用及与GridVie

自学Web开发第十四天-基于VB和ASP.NET;丰富数据呈现:TreeView控件的使用及与GridVie

时间:2019-09-01 00:52:04

相关推荐

自学Web开发第十四天-基于VB和ASP.NET;丰富数据呈现:TreeView控件的使用及与GridVie

自学Web开发第十四天-基于VB和;丰富数据呈现:TreeView控件的使用及与GridView控件联动,深入研究从GridView中取数据

GridView操作数据库后,刷新TreeView控件点击TreeView的节点,GridView的内容跟着改变从GirdView控件中取数据建立空的DataSet和相应DataTable建立表结构,即根据GridView创建表列处理主键列处理数据列复制主键信息准备复制行数据获取单元格内的数据获取行数据

之前研究了一下GridView控件和数据源动态绑定及各种事件,现在想建立个ListBox控件进行联动:选择ListBox上的某项然后可以在GridView里查看详细信息。后来想想将ListBox控件升级,使用树形控件TreeViewGridView联动。

在测试实例中,GridViewTreeView控件绑定到同一个数据库的同一个表,这个表存储的就是TreeView的树形结构。

GridView操作数据库后,刷新TreeView控件

GridView控件进行数据库增、删、改操作后,也就是TreeView的结构有改变,则需要更新TreeView信息。

Private Sub TreeView_Update(ByRef TreeView As TreeView)'读取数据库的节点信息,找出根节点Dim cmdstr As String = "select 节点编号,节点名称 from 节点信息表 where 父节点编号 = 0"Dim tnds As New DataSet'根节点信息表mycon.Open()Dim da As New SqlDataAdapter(cmdstr, mycon)Tryda.Fill(tnds)Catch ex As ExceptionMsgBox("数据库操作错误")Exit SubFinallyda.Dispose()mycon.Close()End Try'清除节点信息TreeView.Nodes.Clear()'给TreeView写入根节点If tnds.Tables(0).Rows.Count > 0 ThenFor Each row As DataRow In tnds.Tables(0).RowsDim NewNode As New TreeNode(row("节点名称"), row("节点编号"))NewNode.PopulateOnDemand = TrueNewNode.SelectAction = TreeNodeSelectAction.SelectExpandNewNode.Expanded = TrueTreeView.Nodes.Add(NewNode)NextEnd If'这里只写入根节点,由于创建的根节点的PopulateOnDemand属性都是True,所有的子节点都在事件TreeNodePopulate中添加TreeView.ExpandAll()tnds.Dispose()End SubPrivate Sub TreeView_TreeNodePopulate(sender As Object, e As TreeNodeEventArgs) Handles TreeView.TreeNodePopulate'读取数据库的节点信息,找出当前节点的子节点Dim cmdstr As String = "select 节点编号,节点名称 from 节点信息表 where 父节点编号 =" & e.Node.ValueDim tnds As New DataSetmycon.Open()Dim da As New SqlDataAdapter(cmdstr, mycon)Tryda.Fill(tnds)Catch ex As ExceptionMsgBox("数据库操作错误")Exit SubFinallyda.Dispose()mycon.Close()End Try'给当前节点写入子节点If tnds.Tables(0).Rows.Count > 0 ThenFor Each row As DataRow In tnds.Tables(0).RowsDim NewNode As New TreeNode(row("节点名称"), row("节点编号"))NewNode.PopulateOnDemand = TrueNewNode.SelectAction = TreeNodeSelectAction.SelectExpandNewNode.Expanded = Truee.Node.ChildNodes.Add(NewNode)NextEnd Iftnds.Dispose()End Sub

点击TreeView的节点,GridView的内容跟着改变

这里在点击TreeView的节点后,GridView显示的是点击节点所在树的数据信息,并且将点击的节点信息移动至第一行。

'选择节点改变的事件Protected Sub TreeView_SelectedNodeChanged(sender As Object, e As EventArgs) Handles TreeView.SelectedNodeChangedDim ds As DataSet = GetTreeDS(TreeView.SelectedNode)'自定义的函数,返回新的数据表。参数是TreeView所选择的节点Bind(ds)End SubPrivate Function GetTreeDS(ByRef CurrentNode As TreeNode) As DataSetDim node As TreeNode = CurrentNodeDim currentValue As Integer = CurrentNode.Value '当前行的值,即节点编号'获取当前节点的根节点While node.Parent IsNot Nothingnode = node.ParentEnd WhileDim NodeList As New ArrayList'用于存储所在树的所有节点的节点编号GetTree(node, NodeList)'自定义函数,递归法历遍所有所在树的节点'数据库查找所有此树下的节点Dim str As String = "'" & NodeList(0) & "'"For i As Integer = 1 To NodeList.Count - 1str += " , '" & NodeList(i) & "'"NextDim cmdstr As String = "select * from 节点信息表 where 节点编号 in ( " & str & " )"Dim ds As New DataSetmycon.Open()Dim da As New SqlDataAdapter(cmdstr, mycon)Tryda.Fill(ds)Catch ex As ExceptionMsgBox("数据库操作错误")Return NothingFinallyda.Dispose()mycon.Close()End Try'将点击的当前节点信息移动至第一行Dim curRow As DataRow = ds.Tables(0).Select("节点编号 = " & currentValue)(0) '查找树状表中,当前节点所在行。因为DataTable.Select()方法返回的是一个行集合,所以加索引号0取第一个值Dim curRowNum As Integer'建一个过渡行,冒泡法提升当前行至第一行Dim dr As DataRow = ds.Tables(0).NewRowWhile ds.Tables(0).Rows.IndexOf(curRow) <> 0curRowNum = ds.Tables(0).Rows.IndexOf(curRow) '当前节点所在行在表中行号'冒泡法交换位置dr.ItemArray = curRow.ItemArraycurRow.ItemArray = ds.Tables(0).Rows(curRowNum - 1).ItemArrayds.Tables(0).Rows(curRowNum - 1).ItemArray = dr.ItemArray'因为交换位置都是指针操作,对于变量指向的行没有变(改变的是行里的数据),所以将所在行变量往上移动一行。curRow = ds.Tables(0).Rows(curRowNum - 1)End WhileReturn dsEnd Function

从GirdView控件中取数据

GridView中写数据使用绑定数据表即可。那么取数据呢?之前的研究中,GridViewRowUpdating事件进行更新数据时候,可以用从CType(GridView.Rows(e.RowIndex).Cells(i).Controls(j),TextBox).Text.ToString.Trim取数据的方法,即将目前行的i + 1列的j + 1个控件转换成TextBox控件,然后取值。这是因为在编辑模式,默认的数据列里的控件转换为TextBox列以供编辑。而模板列因为知道增加的控件ID,所以可以使用CType(GridView.Rows(eRowIndex).FindControl("TextBox"),TextBox).Text.ToString.Trim的方法直接查找行内的控件来取值。那么在非编辑模式怎么取数据呢?即我们怎么从一个GridView控件取其中的数据存成DataSet

建立空的DataSet和相应DataTable

做准备工作,准备存储从GridView获取的数据。

Dim ds As New DataSet'建立空DataSetds.Tables.add()'增加一个空表ds.Tables(0).TableName = "Table"'新建的空表的表名Dim dt As DataTable = ds.Tables("Table")'定义变量指向这个空表

建立表结构,即根据GridView创建表列

因为GridView的单元格里不一定都是数据,有可能是按钮、或者是命令列、CheckBox列等操作用的列,所以这里定义一个整数数组,存储的是要获取的数据列的索引号。然后根据数组建立表结构。

Dim col() As Integer = {1, 2, 4}'设立数据列信息,表示要去索引号为1、2、4的列的数据

处理主键列

因为有些GridView控件的主键并不显示在数据列里,比如ID等。所以需要先获取主键信息,如果主键不在数据列里,则先添加主键列。

'处理主键信息Dim key() As String = Nothing'主键名数组If GridView.DataKeyNames.Count > 0 Then '如果有主键,则需处理主键信息ReDim key(GridView.DataKeyNames.Count - 1) '确认主键数量Array.Copy(GridView.DataKeyNames, key, GridView.DataKeyNames.Count)'复制主键信息Dim cols(Col.Count) As String '数据列名称数组For i = 0 To Col.Count - 1cols(i) = GridView.Columns(Col(i)).HeaderTextNextFor Each k In keyIf Array.IndexOf(cols, k) > -1 Then '索引号为i的主键存在于数据列中OtherFunction.ArrayRemoveAt(key, Array.IndexOf(key, k))'从主键名称数组中抽离End IfNext'这时数组key中的主键均不在数据列里了,在DataTable内先增加主键列For i = 0 To key.Count - 1dt.Columns.Add(key(i), GetType(String))'将主键添加至列NextEnd If

这里使用了一个自定义的函数ArrayRemoveAt(),作用是从数组中抽离目标索引号的元素,具体代码如下:

Public Sub ArrayRemoveAt(Of T)(ByRef arr As T(), ByVal index As Integer)'检查上下标Dim uBound = arr.GetUpperBound(0)Dim lBound = arr.GetLowerBound(0)Dim arrLen = arr.CountIf index < lBound OrElse index > uBound ThenDim Exception As New ArgumentException("索引超出数组上下标界限")Throw ExceptionElse'创建一个元素数量少1的数组,用于存储移除1个元素后的其他元素,减二是因为定义数组的数量使用的是索引上标,'arr(i-1)就是有i个元素,所以定义元素数量少1的数组使用outArr(i-2)Dim outArr(arrLen - 2) As T'复制移除元素前的部分Array.Copy(arr, 0, outArr, 0, index)'复制移除元素后的部分Array.Copy(arr, index + 1, outArr, index, uBound - index)arr = outArrEnd IfEnd SubEnd Module

处理数据列

额外的主键列添加完后,依次添加数据列

'根据col(),设置新表的数据列名For i As Integer = 0 To Col.Count - 1 '处理每个数据列dt.Columns.Add(GridView.Columns(Col(i)).HeaderText, Type.GetType("System.String")) '预设列数据类型为StringNext

复制主键信息

将主键信息(即哪些列是主键)复制给DataTable

'复制主键信息(因为有主键是待处理的数据列,所以在数据列处理完成后再添加主键信息)If GridView.DataKeyNames.Count > 0 ThenDim dc(GridView.DataKeyNames.Count - 1) As DataColumn '定义列集合For i = 0 To GridView.DataKeyNames.Count - 1'找到每个原先的主键列dc(i) = dt.Columns(GridView.DataKeyNames(i))Nextdt.PrimaryKey = dc '确定DataTable的主键End If

准备复制行数据

到这里,表结构基本建立完成了。之所以是基本完成,是因为在填充行数据时,如果有些行使用的是超链接,则动态添加一列用以存储超链接信息。这里用一个长度等于以上准备表列数的映射数组,如果需要增加列,则相应索引映射数组的值指向添加的列的索引值。这样碰到需要添加列的行,则先查询数组相应索引,如果有值,则添加到数据到指向的列,如果无值,则添加列并赋值。

在复制数据时,会循环从每行取数据复制到新表内,所以要设置一个变量保存分页状态,然后取消分页。在复制完数据后,恢复分页状态。

Dim ys(dt.Columns.Count - 1) As String'添加映射数组Dim IsPaging As Boolean = GridView.AllowPaging '设置变量保存分页状态Dim vis As Boolean = GridView.Visible'设置变量保存可见状态Dim sorting As Boolean = GridView.AllowSorting '设置变量保存排序状态GridView.AllowSorting = False '取消排序GridView.AllowPaging = False '取消分页GridView.DataBind()GridView.Visible = True '可见

接下来研究下怎么获取行数据

获取单元格内的数据

我们可以通过GridView.Rows(i).Cells(j)来找到控件中的单元格,但是实际测试中出现了找不到数据的情况。详细研究了一下,发现GridView对于各种Field的处理方式是不一样的。

BoundField在普通模式直接呈现数据,单元格里的控件数量是0。在编辑模式数据放在TextBox控件里,单元格控件数量1。

HyperLinkField任何模式单元格里控件数量都是1。不过好像超链接列没有编辑模式……

ImageField未绑定数据且未显示内容时控件数量是0。在编辑模式数据放在TextBox里,控件数量是1。普通模式下控件数量是2,分别是ImageLabel

CheckBoxField未绑定数据且未显示内容时控件数量是0。在编辑模式会有一个CheckBox,控件数量是1。

ButtonFieldCommandField一般是控制列,不存储数据,不进行研究。

TemplateField模板列比较复杂。它不分绑定数据与否,只是看设计中添加了几个控件。不管普通模式还是编辑模式,所有我们自己添加的控件前后都会增加一个LiteralControl控件。即如果我们添加了一个TextBox控件,则单元格里实际上有3个控件,排列顺序为LiteralControl/TextBox/LiteralControl。如果添加了一个TextBox和一个Label,则单元格里实际上有5个控件,分别为LiteralControl/TextBox/LiteralControl/Label/LiteralControl。所以在使用中需要注意判断。

即在处理过程中,要考虑到当前行是否处于编辑模式,当前单元格是否是模板列。

整体思路为,先判断当前单元格的控件数量。如果是1,则是存储数据的控件,根据控件类型提取数据。如果大于1,则当前单元格是模板列,分析各个控件进行处理和数据提取(可以考虑像超链接列一样增加列)。如果是0,即没有控件或控件没有绑定数据从而不显示出来,则直接从单元格里提取数据(有可能是空)。从控件中提取数据时,如果控件是超链接控件或者图像控件,则增加一列,并记录映射数组。

获取行数据

能判断各单元格里的情况,则可以进行数据获取了。

For i = 0 To GridView.Rows.Count - 1 '处理每行数据Dim keycol As Integer = 0If key IsNot Nothing Then keycol = key.Count '如果有添加的主键列,取其数量'此时,新建表里的列数量为新增加的主键列与需要处理的数据列之和,即 keycol + col.countFor j = 0 To dt.Columns.Count - 1 '循环处理每列If j < keycol Then '列索引从0到 keycol-1 都是新增的主键列dt.Rows(i)(j) = GridView.DataKeys(i)(key(j))'主键的值写入新表Continue ForElse'此时,新表的列索引和GridView的数据列索引数组的索引号相差keycol,即新表索引号为 keycol 时,相对应GridView的数据列索引号为col(0),即 col( j - keycol)Dim cell As TableCell = GridView.Rows(i).Cells(Col(j - keycol))'需处理的GridView的单元格If cell.Controls.Count = 0 Then'单元格中控件数为0,直接取数据dt.Rows(i)(j) = cell.TextElse '单元格中控件数为1或更大,从控件里读取数据Dim value(1) As Stringvalue = GetDataFromControl(cell)dt.Rows(i)(j) = value(0)If value(1) <> "" Then'数据需写到增加列If ys(j) = "" Then'需新建列ys(j) = dt.Columns.Count 'j为当前列索引,ys(j)的值为dt新增列的索引dt.Columns.Add(dt.Columns(j).ColumnName & "的增加列", GetType(String))'增加新列End Ifdt.Rows(i)(ys(j)) = value(1) '指向的新增列写入数据End IfEnd IfEnd IfNextNext

这里使用了一个自定义函数 **GetDataFromControl()**作用就是从单元格里的各控件中获取需要的数据。具体代码如下:

Private Function GetDataFromControl(ByRef cell As TableCell) As String() '从GridView单元格内的控件中读取数据,参数为传址的单元格,返回字符串型数组,为读取到的数据If cell.Controls.Count = 0 Then Return NothingDim str(1) As Stringstr = {"", ""}For Each ctrl In cell.ControlsSelect Case ctrl.GetTypeCase = GetType(LiteralControl)Case = GetType(TextBox)str(0) += CType(ctrl, TextBox).TextCase = GetType(Label)str(0) += CType(ctrl, Label).TextCase = GetType(CheckBox)str(0) += CType(ctrl, CheckBox).CheckedCase = GetType(DropDownList)str(0) += CType(ctrl, DropDownList).SelectedItem.TextCase = GetType(HyperLink)str(0) += CType(ctrl, HyperLink).Textstr(1) = CType(ctrl, HyperLink).NavigateUrlCase = GetType(LinkButton)str(0) += CType(ctrl, LinkButton).Textstr(1) = CType(ctrl, LinkButton).PostBackUrlCase = GetType(Image)str(0) += CType(ctrl, Image).AlternateTextstr(1) = CType(ctrl, Image).ImageUrlCase = GetType(ImageButton)str(0) += CType(ctrl, ImageButton).AlternateTextstr(1) = CType(ctrl, ImageButton).ImageUrlEnd SelectNextReturn strEnd Function

自学Web开发第十四天-基于VB和;丰富数据呈现:TreeView控件的使用及与GridView控件联动 深入研究从GridView中取数据

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。