Option Explicit On Public Class Node #Region "公共变量" Private mstrKey As String Private mstrText As String Private mstrTag As String Private mblnExpanded As Boolean Private mintChildrenCount As Integer Private mintVisibleNodesCount As Integer Private mintLevel As Integer Private mobjNodes As Nodes Private mobjParent As Node Private mobjPrevNode As Node Private mobjNextNode As Node Public IsDirectory As Boolean = False #End Region #Region "Friend 属性" Friend ReadOnly Property AbsIndex() As Integer Get Dim i As Integer Dim tmpNode As Node tmpNode = Me i = 1 Do If tmpNode.PrevNode Is Nothing Then If mobjParent IsNot Nothing Then i = i + mobjParent.AbsIndex End If Exit Do Else tmpNode = tmpNode.PrevNode i = i + 1 + tmpNode.ChildrenCount End If Loop Return i End Get End Property Friend Property PrevNode() As Node Get Return mobjPrevNode End Get Set(ByVal value As Node) mobjPrevNode = value End Set End Property Friend Property NextNode() As Node Get Return mobjNextNode End Get Set(ByVal value As Node) mobjNextNode = value End Set End Property Friend ReadOnly Property Root() As Node Get If mobjParent Is Nothing Then Return Me Else Return mobjParent.Root End If End Get End Property Friend ReadOnly Property VisibleNodesCount() As Integer Get Return mintVisibleNodesCount End Get End Property #End Region #Region "Public属性" Public Property Parent() As Node Get Return mobjParent End Get Set(ByVal value As Node) mobjParent = value End Set End Property Public ReadOnly Property Level() As Integer Get Return mintLevel End Get End Property Public Property Key() As String Get Return mstrKey End Get Set(ByVal Value As String) mstrKey = Value End Set End Property Public Property Text() As String Get Return mstrText End Get Set(ByVal Value As String) mstrText = Value End Set End Property Public Property Tag() As String Get Return mstrTag End Get Set(ByVal Value As String) mstrTag = Value End Set End Property Public ReadOnly Property HasChildren() As Boolean Get If mobjNodes Is Nothing Then Return False Else Return True End If End Get End Property Public ReadOnly Property Nodes() As Nodes Get If mobjNodes Is Nothing Then mobjNodes = New Nodes(Me) End If Return mobjNodes End Get End Property Public ReadOnly Property Expanded() As Boolean Get Return mblnExpanded End Get End Property Public ReadOnly Property Visible() As Boolean Get If mintLevel = 0 Then Return True End If Dim i As Integer Dim tmpNode As Node tmpNode = mobjParent For i = mintLevel To 1 Step -1 If Not tmpNode.Expanded Then Return False End If tmpNode = tmpNode.Parent Next Return True End Get End Property Public ReadOnly Property ChildrenCount() As Integer Get Return mintChildrenCount End Get End Property #End Region #Region "Private方法" Private Sub CopyNode(ByVal SourceNode As Node, ByVal TargetNode As Node) '复制所有的子节点 If Not SourceNode.Expanded Then TargetNode.Collapse() End If If SourceNode.ChildrenCount > 0 Then Dim i As Integer Dim strText As String Dim strTag As String Dim objNode As Node For i = 1 To SourceNode.Nodes.Count With SourceNode.Nodes.Item(i) strText = .Text strTag = .Tag End With objNode = TargetNode.Nodes.Add(strText, strTag) If Not SourceNode.Nodes.Item(i).Expanded Then objNode.Collapse() End If CopyNode(SourceNode.Nodes.Item(i), objNode) Next End If End Sub #End Region #Region "Friend 方法" Friend Sub UpdateChindrenCount(ByVal diff As Integer) '更新子节点数 mintChildrenCount = mintChildrenCount + diff If mobjParent IsNot Nothing Then mobjParent.UpdateChindrenCount(diff) End If End Sub Friend Sub UpdateVisibleNodesCount(ByVal diff As Integer) '更新可见节点数 mintVisibleNodesCount = mintVisibleNodesCount + diff If mobjParent IsNot Nothing Then If mobjParent.Expanded Then mobjParent.UpdateVisibleNodesCount(diff) End If End If End Sub Friend Function FindNextVisibleNode() As Node Return FindNextVisibleNode(False) End Function Friend Function FindNextVisibleNode(ByVal FindNext As Boolean) As Node Dim i As Integer Dim CollapsedNode As Node = Nothing '检查所有父节点是否包含Collapsed节点 If mintLevel > 0 Then Dim tmpNode As Node tmpNode = mobjParent For i = mintLevel To 1 Step -1 If Not tmpNode.Expanded Then CollapsedNode = tmpNode End If tmpNode = tmpNode.Parent Next End If If CollapsedNode IsNot Nothing Then Return CollapsedNode.FindNextVisibleNode End If 'FindNext是指要排除自己的子节点,从下一个节点开始搜索 If (Not FindNext) AndAlso mblnExpanded AndAlso mintChildrenCount > 0 Then Return mobjNodes.FirstNode End If If mobjNextNode Is Nothing Then If mobjParent Is Nothing OrElse mintLevel = 1 Then Return Nothing Else Return mobjParent.FindNextVisibleNode(True) End If Else Return mobjNextNode End If End Function Friend Function FindLastVisibleChildNode() As Node If mintVisibleNodesCount = 1 Then Return Me Else Return mobjNodes.LastNode.FindLastVisibleChildNode End If End Function Friend Function FindPrevVisibleNode() As Node Dim i As Integer Dim CollapsedNode As Node = Nothing '检查所有父节点是否包含Collapsed节点 If mintLevel > 0 Then Dim tmpNode As Node tmpNode = mobjParent For i = mintLevel To 1 Step -1 If Not tmpNode.Expanded Then CollapsedNode = tmpNode End If tmpNode = tmpNode.Parent Next End If If CollapsedNode IsNot Nothing Then Return CollapsedNode End If If mobjPrevNode IsNot Nothing Then Return mobjPrevNode.FindLastVisibleChildNode Else If mobjParent Is Nothing Then Return Nothing Else Return mobjParent End If End If End Function #End Region #Region "Public方法" Public Sub New() mstrKey = "" mstrText = "" mstrTag = "" mintLevel = 0 mblnExpanded = True mintChildrenCount = 0 mintVisibleNodesCount = 1 End Sub Public Sub New(ByVal Key As String, ByVal Text As String, ByVal Tag As String, ByVal Level As Integer, ByVal Parent As Node) mstrKey = Key mstrText = Text mstrTag = Tag mintLevel = Level mobjParent = Parent mblnExpanded = True mintChildrenCount = 0 mintVisibleNodesCount = 1 End Sub Public Sub Collapse() If (mintLevel = 0) OrElse (Not mblnExpanded) Then Return End If mblnExpanded = False UpdateVisibleNodesCount(1 - mintVisibleNodesCount) End Sub Public Sub Expand() If mblnExpanded Then Return End If Dim i As Integer mblnExpanded = True If mobjNodes IsNot Nothing Then For i = 1 To mobjNodes.Count UpdateVisibleNodesCount(mobjNodes.Item(i).VisibleNodesCount) Next End If End Sub Public Sub ExpandAll() Expand() Dim i As Integer If mobjNodes IsNot Nothing Then For i = 1 To mobjNodes.Count mobjNodes.Item(i).ExpandAll() Next End If End Sub Public Sub LevelUp() '升级规则:成为父节点的NextNode If mobjParent.Level = 1 Then Return End If Dim objNode As Node = mobjParent.Parent.Nodes.InsertAfter(mobjParent.Key, mstrText, mstrTag) CopyNode(Me, objNode) mobjParent.Nodes.Remove(mstrKey) End Sub Public Sub LevelDown() '降级规则:成为PrevNode的最后一个子节点 If mobjPrevNode Is Nothing Then Return End If Dim objNode As Node = mobjPrevNode.Nodes.Add(mstrText, mstrTag) CopyNode(Me, objNode) mobjParent.Nodes.Remove(mstrKey) End Sub Public Sub MoveUp() '上移规则:和PrevNode交换位置 If mobjPrevNode Is Nothing Then Return End If Dim objNode As Node = mobjParent.Nodes.InsertBefore(mobjPrevNode.Key, mstrText, mstrTag) CopyNode(Me, objNode) mobjParent.Nodes.Remove(mstrKey) End Sub Public Sub MoveDown() '下移规则:和NextNode交换位置 If mobjNextNode Is Nothing Then Return End If Dim objNode As Node = mobjParent.Nodes.InsertAfter(mobjNextNode.Key, mstrText, mstrTag) CopyNode(Me, objNode) mobjParent.Nodes.Remove(mstrKey) End Sub Public Function FindNode(ByVal Index As Integer) As Node '根据绝对位置定位Node If Index = 1 Then Return Me End If Dim i As Integer = Index - 1 If Me.ChildrenCount >= i Then Return Me.Nodes.FirstNode.FindNode(i) Else i = i - Me.ChildrenCount If Me.NextNode Is Nothing Then Return Nothing Else Return Me.NextNode.FindNode(i) End If End If End Function #End Region End Class