PD1991
Member
- Joined
- Nov 17, 2021
- Messages
- 18
- Programming Experience
- 1-3
Hello,
How can I filter treeview in winforms on textBox change event using C# ? I want to check hide or remove nodes from treeview If filter string not matched. In my case, treeview may have multiple levels so filter should work at multiple levels.
I found on the solution which matches my requirement but Its in VB.Net (Sign in - CodeProject) and I am finding it hard to convert it into C#.
Any help please.
How can I filter treeview in winforms on textBox change event using C# ? I want to check hide or remove nodes from treeview If filter string not matched. In my case, treeview may have multiple levels so filter should work at multiple levels.
I found on the solution which matches my requirement but Its in VB.Net (Sign in - CodeProject) and I am finding it hard to convert it into C#.
Any help please.
Code Block 1:
Public Class cTreeNode
Inherits TreeNode
Friend _MyTreeNodeCollection As cTreeNodeCollection
Public Shadows Nodes As New cTreeNodeCollection(MyBase.Nodes)
Public Sub New()
MyBase.New()
End Sub
Public Sub New(Text As String)
MyBase.New(Text)
End Sub
Public Sub New(Text As String, Children() As cTreeNode)
MyBase.New(Text)
For Each N In Children
Me.Nodes.Add(N)
Next
End Sub
Public Shadows ReadOnly Property TreeView() As cTreeView
Get
Return MyBase.TreeView
End Get
End Property
Private _Hidden As Boolean
Public Property Hidden(Optional CascadeUp As Boolean = True, Optional CascadeDown As Boolean = False) As Boolean
Get
Return _Hidden
End Get
Set(ByVal value As Boolean)
If CascadeUp Then
Dim P As cTreeNode = MyBase.Parent
Do While P IsNot Nothing
Dim Res = TreeView.CascadeNodeEventRaiser(Me, P)
If Res.CancelCascade Then Exit Do
If Res.Handled = False Then
'we set CascadeUp to false and cycle through all parents manually to be able to pass in CascadeNodeEventRaiser the real originating node of those callings
P.Hidden(False) = value
P = P.Parent
End If
Loop
'End If
End If
If CascadeDown Then CascadeCollection(Me.Nodes, value)
'Do nothing if value didn't really changed, to increase performance.
If _Hidden <> value Then
_Hidden = value
If Me.InCollection Then
If _Hidden = True Then
_MyTreeNodeCollection._VisibleNodes.Remove(Me)
Else
'if we making the node visible, put it after closer visible node
If Me.PreviousUnHidenNode Is Nothing Then
_MyTreeNodeCollection._VisibleNodes.Insert(0, Me)
Else
_MyTreeNodeCollection._VisibleNodes.Insert(Me.PreviousUnHidenNode.VisibilityIndex + 1, Me)
End If
End If
End If
End If
End Set
End Property
'This is a recruceve procedure that will cascade down all nodes
Private Sub CascadeCollection(NDC As cTreeNodeCollection, IsHidden As Boolean)
For Each N As cTreeNode In NDC
Dim Res = TreeView.CascadeNodeEventRaiser(Me, N)
If Res.CancelCascade Then Exit For
If Res.Handled = False Then
N.Hidden(False, False) = IsHidden
If N.Nodes.Count > 0 Then CascadeCollection(N.Nodes, IsHidden)
End If
Next
End Sub
'This will return the closest previous unHidden node
Friend ReadOnly Property PreviousUnHidenNode() As cTreeNode
Get
If Me.Index = 0 Then
Return Nothing
Else
If Me.InCollection = False Then
Throw New Exception("This node is not assigned to a TreeNodeCollection yet.")
Else
For i = Me.Index - 1 To 0 Step -1
If _MyTreeNodeCollection(i).Hidden = False Then Return _MyTreeNodeCollection(i)
Next
End If
End If
End Get
End Property
'This will return node index as it visible on TreeView
Public ReadOnly Property VisibilityIndex As Integer
Get
Return MyBase.Index
End Get
End Property
'This will return node index as it is in the Actual node list
Public Shadows ReadOnly Property Index As Integer
Get
If Me.InCollection Then
Return _MyTreeNodeCollection._ActualNodes.IndexOf(Me)
Else
Throw New Exception("This node is not assigned to a TreeNodeCollection yet.")
End If
End Get
End Property
'just a help property to check if tree node assigned to some tree collection
Friend ReadOnly Property InCollection As Boolean
Get
Return _MyTreeNodeCollection IsNot Nothing
End Get
End Property
End Class
Code Block 2:
Public Class cTreeNodeCollection
'Make class usable with For...Each
Implements IEnumerable
Friend _VisibleNodes As TreeNodeCollection
Friend _ActualNodes As New List(Of cTreeNode)
Friend Sub New(TreeNodeCollection As TreeNodeCollection)
_VisibleNodes = TreeNodeCollection
End Sub
'This is to mimic original TreeNodeCollection behavior
Default Public ReadOnly Property Items(Index As Integer) As cTreeNode
Get
Return _ActualNodes(Index)
End Get
End Property
Public Sub Add(Node As cTreeNode)
Node._MyTreeNodeCollection = Me
_ActualNodes.Add(Node)
'if the node is Hidden, there is no need to add it to TreeNodeCollection
If Node.Hidden = False Then _VisibleNodes.Add(Node)
End Sub
Public Sub AddRange(Nodes() As cTreeNode)
For Each N In Nodes
Add(N)
Next
End Sub
Public Sub Remove(Node As cTreeNode)
Node._MyTreeNodeCollection = Nothing
_ActualNodes.Remove(Node)
_VisibleNodes.Remove(Node)
End Sub
Public ReadOnly Property Count As Integer
Get
Return _ActualNodes.Count
End Get
End Property
Public ReadOnly Property VisibleCount As Integer
Get
Return _VisibleNodes.Count
End Get
End Property
Public Sub Insert(Node As cTreeNode, Index As Integer)
_ActualNodes.Insert(Index, Node)
If Node.Hidden = False Then
'If there is no unHidden nodes at same level, add it just at the beginning
If Node.PreviousUnHidenNode Is Nothing Then
_VisibleNodes.Insert(0, Node)
Else
_VisibleNodes.Insert(Node.PreviousUnHidenNode.VisibilityIndex, Node)
End If
End If
End Sub
#Region "Implementing IEnumerable"
Public Function GetEnumerator() As IEnumerator Implements IEnumerable.GetEnumerator
Return New cMyEnumerator(_ActualNodes)
End Function
Private Class cMyEnumerator
Implements IEnumerator
Public Nodes As List(Of cTreeNode)
Private position As Integer = -1
'constructor
Public Sub New(ByVal ActualNodes As List(Of cTreeNode))
Nodes = ActualNodes
End Sub
Private Function getEnumerator() As IEnumerator
Return DirectCast(Me, IEnumerator)
End Function
'IEnumerator
Public Function MoveNext() As Boolean Implements IEnumerator.MoveNext
position += 1
Return (position < Nodes.Count)
End Function
'IEnumerator
Public Sub Reset() Implements IEnumerator.Reset
position = -1
End Sub
'IEnumerator
Public ReadOnly Property Current() As Object Implements IEnumerator.Current
Get
Try
Return Nodes(position)
Catch e1 As IndexOutOfRangeException
Throw New InvalidOperationException()
End Try
End Get
End Property
End Class 'end nested class
#End Region
End Class
Code Block 3:
Public Class cTreeView
Inherits Windows.Forms.TreeView
#Region "Cascade Event"
Public Event CascadeNode(sender As Object, e As EventArgs)
Friend Function CascadeNodeEventRaiser(NDSource As cTreeNode, NDCurrent As cTreeNode) As CascadeNodeEventArgs
Dim EA = New CascadeNodeEventArgs(NDSource, NDCurrent)
RaiseEvent CascadeNode(Me, EA)
Return EA
End Function
Public Class CascadeNodeEventArgs
Inherits EventArgs
Public Sub New(NDSource As cTreeNode, NDCurrent As cTreeNode)
_CascadeNode = NDCurrent
_TrigerNode = NDSource
End Sub
'If this set to True, the whole cascading operation will be canceled.
Private _CancelCascade As Boolean
Public Property CancelCascade() As Boolean
Get
Return _CancelCascade
End Get
Set(ByVal value As Boolean)
_CancelCascade = value
End Set
End Property
Private _CascadeNode As cTreeNode
Public ReadOnly Property CascadeNode() As cTreeNode
Get
Return _CascadeNode
End Get
End Property
Private _TrigerNode As cTreeNode
Public ReadOnly Property TrigerNode() As cTreeNode
Get
Return _TrigerNode
End Get
End Property
Private _Handled As Boolean
Public Property Handled() As Boolean
Get
Return _Handled
End Get
Set(ByVal value As Boolean)
_Handled = value
End Set
End Property
End Class
#End Region
'Redefining native Node collection
Public Shadows ReadOnly Nodes As New cTreeNodeCollection(MyBase.Nodes)
#Region "Filtering"
'delegate that will decide what to keep visible
Public Delegate Function Selector(Node As cTreeNode) As Boolean
Public Shadows Property SelectedNode() As cTreeNode
Get
Return MyBase.SelectedNode
End Get
Set(ByVal value As cTreeNode)
MyBase.SelectedNode = value
End Set
End Property
Public Sub Filter(Filter As Selector)
_Filter(Filter, Me.Nodes)
End Sub
'The recursive Filtering procedure
Private Sub _Filter(Filter As Selector, NDC As cTreeNodeCollection)
For Each ND In NDC._ActualNodes
'Before anything else, if we have subNodes, go and filter them first
If ND.Nodes._ActualNodes.Count > 0 Then _Filter(Filter, ND.Nodes)
If Filter(ND) Then
ND.Hidden(False) = False
Else
'if current node has at least one visible node after filtering, make the parent visible too
ND.Hidden(False) = ND.Nodes._VisibleNodes.Count = 0
End If
Next
End Sub
#End Region
End Class
Last edited: