0 Replies - 1900 Views - Last Post: 27 December 2014 - 02:26 AM

#1 djjeavons   User is offline

  • D.I.C Regular
  • member icon

Reputation: 114
  • View blog
  • Posts: 417
  • Joined: 09-January 09

Checking and unchecking child and parent nodes within a TreeView

Posted 27 December 2014 - 02:26 AM

Hi

This snippet demonstrates how to check and uncheck both child and parent nodes within a TreeView control based on where in the hierarchy a node was first checked.

For example, given the following structure:

Root Node
Parent 1
Child 1
Child 2
Parent 2
Child 1

Checking Child 1 in Parent 1 will also check Parent 1 and Root Node. Alternatively, checking Parent 1 will check all child nodes under Parent 1.

Disclaimer
There is a problem with the standrd Windows Form Tree View control in that if you doule click a node you will experience some incosnistent behaviour. For example, you may click a child node and it will work fine, but if you double click it, the child node will not necessarily be affected but the parent node(s) may be, giving an inconsistent UI behaviour. This is a known bug from Windows Vista which has carried forward to Windows 7 (not sure about Windows 8, not tested). This bug apparently may not be fixed due to Windows Presentation Foundation (WPF) becoming the new standard for desktop UI's.

So, if you want to implement the ability to check and uncheck child/parent nodes without this bug, the first thing you will have to do is to create a class that inherits from the TreeView control, and implements the ability to suppress the double click when a node is clicked.

The Code
To get starterd, create a new Windows Form Project. Add a class to your project called MyTreeView and in the class add the following code:

Imports System.Windows.Forms

Public Class MyTreeView
    Inherits TreeView

    Protected Overrides Sub WndProc(ByRef m As Message)
        ' Suppress WM_LBUTTONDBLCLK
        If m.Msg = &H203 Then
            m.Result = IntPtr.Zero
        Else
            MyBase.WndProc(m)
        End If
    End Sub

End Class



The above is our TreeView control (courtesy of http://stackoverflow...nodes-problem).

Now, we will implement the code. Oppen the code view for Form1, and add the following to the load event of the form to add the Tree View (the custom version) control and some test data to it.

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load

        'Create a new TreeView control based on the MyTreeView class, 
        Dim myTreeView As New MyTreeView
        myTreeView.Dock = DockStyle.Fill
        Me.Controls.Add(myTreeView)

        'Add some nodes to the Tree View 
        Dim rootNode As New TreeNode("Root")
        Dim parentNode As New TreeNode("Parent 1")
        Dim childNode As TreeNode
        Dim grandchildNode As TreeNode

        For i As Integer = 1 To 5
            childNode = New TreeNode("Child " & i.ToString)

            For x As Integer = 1 To 3
                grandchildNode = New TreeNode("Grandchild " & x.ToString)
                childNode.Nodes.Add(grandchildNode)
            Next

            parentNode.Nodes.Add(childNode)
        Next

        rootNode.Nodes.Add(parentNode)

        parentNode = New TreeNode("Parent 2")

        For i As Integer = 6 To 8
            childNode = New TreeNode("Child " & i.ToString)

            For x As Integer = 1 To 3
                grandchildNode = New TreeNode("Grandchild " & x.ToString)
                childNode.Nodes.Add(grandchildNode)
            Next

            parentNode.Nodes.Add(childNode)
        Next

        rootNode.Nodes.Add(parentNode)

        myTreeView.Nodes.Add(rootNode)
        myTreeView.CheckBoxes = True
        myTreeView.ExpandAll()
        AddHandler myTreeView.AfterCheck, AddressOf myTreeView_AfterCheck

    End Sub



The AfterCheck event

Add the following code to the AfterCheck event of the TreeView control:

Private Sub myTreeView_AfterCheck(sender As Object, e As TreeViewEventArgs)

	If Not e.Action = TreeViewAction.Unknown Then
		NodesSetChecked(e.Node, e.Node.Checked)
		ParentNodesSetChecked(e.Node, e.Node.Checked)
	End If

End Sub



Note in the above code how the Action property of the TreeViewEventArgs is checked to ensure that the action is from a known source such as a mouse click or keyboard message. Without this, we could end up with a StackOverFlowException due to the setting of the check state of further nodes which will fire this event over and over again.

The NodesSetChecked routine

Add the following code below the Aftercheck event:

Private Sub NodesSetChecked(treeNode As TreeNode, checkedState As Boolean)

	For Each childNode As TreeNode In treeNode.Nodes
		childNode.Checked = checkedState
		NodesSetChecked(childNode, checkedState)
	Next

End Sub



The above code will enumerate all nodes within the TreeNode passed and set their checked property accordingly. This routine is called recursively for each set of child nodes found.

The ParentNodesSetChecked routine

Finally, add the following code below the NodesSetChecked routine:

Private Sub ParentNodesSetChecked(treeNode As TreeNode, checkedState As Boolean)

	If treeNode.Parent IsNot Nothing Then

		'If the checkedState is False then we should first determine if any children have a checked 
		'state of true before unchecking the parent
		If checkedState = False Then
			treeNode.Parent.Checked = checkedState
			For Each childNode As TreeNode In treeNode.Parent.Nodes
				If childNode.Checked = True Then
					treeNode.Parent.Checked = True
					Exit For
				End If
			Next
		Else
			treeNode.Parent.Checked = checkedState
		End If

		If treeNode.Parent.Parent IsNot Nothing Then ParentNodesSetChecked(treeNode.Parent, checkedState)

	End If

End Sub



The above code is responsible for determining if any parent nodes require checking or unchecking.

That's it.


HTH

This post has been edited by AdamSpeight2008: 11 January 2015 - 09:06 PM


Is This A Good Question/Topic? 0
  • +

Page 1 of 1