当前位置:主页   - 电脑 - 程序设计 - VB
VB.NET中层次数据绑定TreeView的实现
来源:网络   作者:佚名   更新时间:2011-07-18
收藏此页】    【字号    】    【打印】    【关闭

  提要:在VB6中,常将TreeView用来表示层次数据,但相关的与数据库进行交互的代码,需要大量的采用手工编码;在VB.net中,由于数据绑定功能的加强及语言特性的增强,可以很容易的实现TreeView与层次数据的绑定,本文将首先建立一个继承自TreeView的 dbTreeView,然后用一个单位(部门)的层次数据与dbTreeView进行数据绑定,并提供了与数据库进行交互的代码。

  1、从层次数据的表达方式开始

  在本例中,部门表(department)中有五个字段,如下表:

字段名字段类型说明
ID自动编号Key
CodeString编码
NameString名称
PIDInt父结点的ID
CPtrboolean是否有子结点
  

  2、继承自TreeNode的myTreeNode

  在myTreeNode中,新增了三个属性,如下表:

属性名类型说明
ValueObjectKey
PIDObject父结点的ID
CPtrBoolean是否有子结点
  

  在Init事件中,根据传入的四个参数,设置这三个属性和Text属性。

  3、将dbTreeView绑定到数据源

属性名类型说明
DatasourcedataviewdbTreeVIew的数据源使用dataview,而不是object
ValueMemberstring值成员(数据源[dataview]的列名)
DisplayMemberstring显示(在Text中)成员
PidMemberstring父ID成员
CPtrMemberstring是否有子结点
  

  后四个属性对应myTreeNode的value,text,pid,cptr。

  相关代码如下:

  Protected Property DataSource() As Object

  Get

  Return mDataView

  End Get

  Set(ByVal Value As Object)

  If Value Is Nothing Then

  Else

  mDataView = Value

  cm = CType(Me.BindingContext(mDataView), CurrencyManager)

  UpdateTreeView()

  End If

  End Set

  End Property

  Protected Property PidMember() As String

  Get

  Return mPidMember

  End Get

  Set(ByVal Value As String)

  mPidMember = Value

  End Set

  End Property

  Protected Property DisplayMember() As String

  Get

  Return Join(mDisplayMember, SplitChar)

  End Get

  Set(ByVal Value As String)

  mDisplayMember = Split(Value, SplitChar)

  End Set

  End Property

  '注意,这几个属性都是保护成员,必须在Init事件中设置:

Public Sub Init(ByVal dispmember As String, ByVal valuemember As String, ByVal pidmember As String, ByVal cptrmember As String, ByVal datasource As DataView)
 Me.ValueMember = valuemember
 Me.DisplayMember = dispmember
 Me.PidMember = pidmember
 Me.CPtrMember = cptrmember
 Me.DataSource = datasource
 '取value最大值,新增时将value+1,保证关健值唯一。
 Me.mDataView.Sort = Me.ValueMember
 Me.m_MaxID = Me.GetValue(Me.mDataView.Count - 1)
End Sub

  设置DisplayMember属性的格式如:字段1;字段2;字段3…

  在设置属性时,将传来的参数转换为字符串数组mDisplayMember,在检索值时返回数据如:值1 值2 值3.…

Protected Overridable Function GetDisplay(ByVal Index As Integer) As Object
 Dim i As Integer
 Dim temp As String = ""
 For i = 0 To mDisplayMember.Length - 1
  temp = temp & IIf(i > 0, LinkChar, "") & mDataView(Index)(mDisplayMember(i))
 Next
 Return temp
End Function

  其它检索值的函数请参见源程序。

  生成树

  UpdateTreeView调用私有方法FillTree来生成树,需要注意的,FillTree只是生成指定结点的子结点并将其添加到指定结点,而不是一次就将所有结点添加到树中,如果未指定结点(第一次填充时),只是添加顶层结点。

Private Sub FillTree(ByRef pnode As myTreeNode, Optional ByVal filter As String = "")
 mDataView.RowFilter = filter
 Dim i As Integer, icol As Integer
 Dim newnode As myTreeNode
 RemoveHandler cm.PositionChanged, AddressOf cm_PositionChanged
 Me.BeginUpdate()
 For i = 0 To mDataView.Count() - 1
  newnode = New myTreeNode(GetDisplay(i), GetValue(i), GetPid(i), GetCPtr(i))
  '当有子结点时,为这个结点添加一个空子结点
  If newnode.CPtr Then
   Dim nullnode As New myTreeNode()
   nullnode.Value = NoExpandNodeValue
   newnode.Nodes.Add(nullnode)
  End If
  If pnode Is Nothing Then
   Me.Nodes.Clear()
   Me.Nodes.Add(newnode)
  Else
   pnode.Nodes.Add(newnode)
  End If
 Next
 Me.EndUpdate()
 mDataView.RowFilter = ""
 AddHandler cm.PositionChanged, AddressOf cm_PositionChanged
End Sub

  在展开有子结点的结点前,删除所有子结点,再用FillTree为待展开结点新增子结点。

Private Sub dbTreeView_BeforeExpand(ByVal sender As Object, ByVal e As System.Windows.Forms.TreeViewCancelEventArgs) Handles MyBase.BeforeExpand
 '当是新增结点引起BeforeExpand事件时,直接退出。
 If ExpandWhenAddNode Then Exit Sub
 '在展开结点前更新子结点
 Dim currentnode As myTreeNode = CType(e.Node, myTreeNode)
 With currentnode
  .Nodes.Clear()
  FillTree(currentnode, mPidMember & "= " & CInt(.Value))
 End With
End Sub

  4、实现数据与绑定控件的同步

  要实现两个方面的同步:

  1、 其它绑定控件(如textbox等)应与TreeView当前结点所指向的记录位置一致。

Private Sub dbTreeView_AfterSelect(ByVal sender As Object, ByVal e As System.Windows.Forms.TreeViewEventArgs) Handles MyBase.AfterSelect

 If e.Node Is Nothing Then Exit Sub
 '定位到position
 cm.Position = GetPosition(CType(e.Node, myTreeNode).Value)
 If AllowEdit Then
  oldNode = e.Node
  oldPos = cm.Position
 End If
End Sub

  2、在其它绑定控件改变了数据源后,更新树结点,这个工作在触发CurrencyManager的PositionChanged事件时进行。

Public Sub cm_PositionChanged(ByVal sender As Object, ByVal e As System.EventArgs)
 If CType(Me.SelectedNode, myTreeNode).Value <> GetValue(cm.Position) Then
  Debug.WriteLine("Current node isn't correct point to currencymanager.position!")
  Me.SelectedNode = FindNodeByValue(GetValue(cm.Position), Me.Nodes)
 End If
 If AllowEdit Then
  If Me.SelectedNode Is Nothing AndAlso cm.Position = cm.Count - 1 Then
   '当新增记录时,新增树结点
   If CType(cm.Current, DataRowView).IsNew Then
    Me.SelectedNode = AddNode(cm.Position)
    Exit Sub
   End If
  End If
  If Not oldNode Is Nothing Then
   If CType(oldNode, myTreeNode).Value = GetValue(oldPos) Then
    '更新老结点
    oldNode.Text = GetDisplay(oldPos)
   Else
   End If
  End If
 End If
End Sub

  使用dbTreeView

  程序运行后界面如下:

VB.NET中层次数据绑定TreeView的实现

  图片看不清楚?请点击这里查看原图(大图)。

  相关代码请参见源程序,这里不做详述,

  需要注意的是删除操作并没有删除子结点,只是删除当前结点而已,删除子结点的工作应该在存储过程中递归实现,而不应放在前端。

其它资源
来源声明

版权与免责声明
1、本站所发布的文章仅供技术交流参考,本站不主张将其做为决策的依据,浏览者可自愿选择采信与否,本站不对因采信这些信息所产生的任何问题负责。
2、本站部分文章来源于网络,其版权为原权利人所有。由于来源之故,有的文章未能获得作者姓名,署“未知”或“佚名”。对于这些文章,有知悉作者姓名的请告知本站,以便及时署名。如果作者要求删除,我们将予以删除。除此之外本站不再承担其它责任。
3、本站部分文章来源于本站原创,本站拥有所有权利。
4、如对本站发布的信息有异议,请联系我们,经本站确认后,将在三个工作日内做出修改或删除处理。
请参阅权责声明