LIDOR SYSTEMS

Advanced User Interface Controls and Components

Display Three State Checkboxes in TreeView .NET Control

Created: Mar 05, 2009

Updated: Jun 01, 2013

By default the IntegralUI TreeView displays two states of the checkboxes in each node. By setting the CheckMode property to ThreeState, every check box can display one of these three states: Unchecked, Indeterminate and Checked.

treeview with tri-state checkboxes
Download free sample

However, the check box value is not automatically updated for any child or parent node. To do that, the AfterCheck event needs to be handled. Here is how:

At first you need to have a TreeView with some root nodes and child nodes in it. Also nodes must have check box visible and the tri-state mode enabled. In the following code we will create a small tree hierarchy:

private void InitList()

{

// Suspend the treeview layout to increase performance

this.treeView1.SuspendUpdate();

this.treeView1.Nodes.Clear();

 

// Make sure the check boxes are displayed, and they accepts three values

this.treeView1.CheckBoxes = true;

this.treeView1.CheckMode = LidorSystems.IntegralUI.CheckMode.ThreeState;

 

LidorSystems.IntegralUI.Lists.TreeNode node = null;

for (int i = 0; i < 10; i++)

{

// Create a new node

node = new LidorSystems.IntegralUI.Lists.TreeNode("Node " + i.ToString());

 

// Create a child nodes for this node

CreateChildNodes(node, 0);

 

// Add the node as the root node

this.treeView1.Nodes.Add(node);

}

 

// Resume the treeview layout and update the control

this.treeView1.ResumeUpdate();

}

 

private void CreateChildNodes(LidorSystems.IntegralUI.Lists.TreeNode parentNode, int level)

{

//In this example only 2 levels in hierarchy are allowed

if (level == 2)

return;

else

{

LidorSystems.IntegralUI.Lists.TreeNode node = null;

for (int i = 0; i < 3; i++)

{

// Create a new child node

node = new LidorSystems.IntegralUI.Lists.TreeNode("Node " + level.ToString() + i.ToString());

 

// Create a child nodes for this node

CreateChildNodes(node, level + 1);

 

// Add the node to the parent node

parentNode.Nodes.Add(node);

}

}

}

Private Sub InitList()

' Suspend the treeview layout to increase performance

Me.treeView1.SuspendUpdate()

Me.treeView1.Nodes.Clear()

 

' Make sure the check boxes are displayed, and they accepts three values

Me.treeView1.CheckBoxes = True

Me.treeView1.CheckMode = LidorSystems.IntegralUI.CheckMode.ThreeState

 

Dim node As LidorSystems.IntegralUI.Lists.TreeNode = Nothing

For i As Integer = 0 To 9

' Create a new node

node = New LidorSystems.IntegralUI.Lists.TreeNode("Node " & i.ToString())

 

' Create a child nodes for this node

CreateChildNodes(node, 0)

 

' Add the node as the root node

Me.treeView1.Nodes.Add(node)

Next

 

' Resume the treeview layout and update the control

Me.treeView1.ResumeUpdate()

End Sub

 

Private Sub CreateChildNodes(ByVal parentNode As LidorSystems.IntegralUI.Lists.TreeNode, ByVal level As Integer)

'In this example only 2 levels in hierarchy are allowed

If level = 2 Then

Exit Sub

Else

Dim node As LidorSystems.IntegralUI.Lists.TreeNode = Nothing

For i As Integer = 0 To 2

' Create a new child node

node = New LidorSystems.IntegralUI.Lists.TreeNode(("Node " & level.ToString()) + i.ToString())

 

' Create a child nodes for this node

CreateChildNodes(node, level + 1)

 

' Add the node to the parent node

parentNode.Nodes.Add(node)

Next

End If

End Sub

Then by handling the AfterCheck event, we will cycle through child and parent nodes and change the value of their check box. The UpdateChild method is used to change the check box value of the child nodes, while UpdateParent method is used to change the check box value of the parent nodes.

In order to avoid callback internally whenever a value of check box s changed when AfterCheck event is called, we will use a variable which determines whether the event is already called or not.

private bool suspendCallBack = false;

 

. . .

 

private void treeView1_AfterCheck(object sender, LidorSystems.IntegralUI.ObjectEventArgs e)

{

if (!suspendCallBack && e.Object is LidorSystems.IntegralUI.Lists.TreeNode)

{

LidorSystems.IntegralUI.Lists.TreeNode node = (LidorSystems.IntegralUI.Lists.TreeNode)e.Object;

 

// Suspend the further calling of BeforeCheck and AfterCheck events

suspendCallBack = true;

 

// Use this method to update the state for all child nodes of this node

UpdateChild(node);

 

// Use this method to update the state for all parent nodes of this node

UpdateParent(node);

 

// Resume the calling of BeforeCheck and AfterCheck events

suspendCallBack = false;

}

}

 

private void UpdateChild(LidorSystems.IntegralUI.Lists.TreeNode node)

{

// If the parent node is not Indeterminate

// change the state of all child nodes

if (node.CheckState != CheckState.Indeterminate)

{

CheckState state = node.CheckState;

foreach (LidorSystems.IntegralUI.Lists.TreeNode childNode in node.Nodes)

{

if (childNode.Visible)

{

// Change the CheckState of the childNode

childNode.CheckState = state;

 

// Repeat the whole cycle for other child nodes

UpdateChild(childNode);

}

}

}

}

 

private void UpdateParent(LidorSystems.IntegralUI.Lists.TreeNode node)

{

// Hold te number of unchecked and visible nodes

int numUnchecked = 0;

int numVisible = 0;

 

// Let presume that by default that node is checked

CheckState state = CheckState.Checked;

 

// Get the parent node

LidorSystems.IntegralUI.Lists.TreeNode parentNode = node.Parent;

while (parentNode != null)

{

numUnchecked = 0;

numVisible = 0;

 

state = CheckState.Checked;

foreach (LidorSystems.IntegralUI.Lists.TreeNode childNode in parentNode.Nodes)

{

if (childNode.Visible)

{

numVisible++;

// If there is at least one Indeterminate node, exit the loop.

// The state for the parent node will be also Indeterminate

if (childNode.CheckState == CheckState.Indeterminate)

{

state = CheckState.Indeterminate;

break;

}

// Count the unchecked nodes

else if (childNode.CheckState == CheckState.Unchecked)

numUnchecked++;

}

}

 

if (numVisible > 0)

{

// If there are no unchecked nodes and there is at least one indeterminate node,

// that means that all child nodes are checked. So, the parent node will also be Checked

if (numUnchecked == 0 && state != CheckState.Indeterminate)

state = CheckState.Checked;

// If number of visible and unchecked nodes are equal, then parent node will be Unchecked

else if (numUnchecked == numVisible)

state = CheckState.Unchecked;

// In any other case, then parent node will be Indeterminate

else

state = CheckState.Indeterminate;

}

// If there are no visible nodes, the parent node will be unchecked

else

state = CheckState.Unchecked;

 

// Change the CheckState of the parent node,

parentNode.CheckState = state;

 

// Repeat the whole cycle for other parent nodes

parentNode = parentNode.Parent;

}

}

Private suspendCallBack as Boolean = False

 

. . .

 

Private Sub treeView1_AfterCheck(ByVal sender As Object, ByVal e As LidorSystems.IntegralUI.ObjectEventArgs)

If Not suspendCallBack AndAlso TypeOf e.Object Is LidorSystems.IntegralUI.Lists.TreeNode Then

Dim node As LidorSystems.IntegralUI.Lists.TreeNode = DirectCast(e.Object, LidorSystems.IntegralUI.Lists.TreeNode)

 

' Suspend the further calling of BeforeCheck and AfterCheck events

suspendCallBack = True

 

' Use this method to update the state for all child nodes of this node

UpdateChild(node)

 

' Use this method to update the state for all parent nodes of this node

UpdateParent(node)

 

' Resume the calling of BeforeCheck and AfterCheck events

suspendCallBack = False

End If

End Sub

 

Private Sub UpdateChild(ByVal node As LidorSystems.IntegralUI.Lists.TreeNode)

' If the parent node is not Indeterminate

' change the state of all child nodes

If node.CheckState <> CheckState.Indeterminate Then

Dim state As CheckState = node.CheckState

For Each childNode As LidorSystems.IntegralUI.Lists.TreeNode In node.Nodes

If childNode.Visible Then

' Use this method to change the CheckState of the childNode,

' without triggerring the BeforeCheck and AfterCheck events

' this.treeView1.ChangeCheckState(childNode, state);

 

childNode.CheckState = state

 

' Repeat the whole cycle for other child nodes

UpdateChild(childNode)

End If

Next

End If

End Sub

 

Private Sub UpdateParent(ByVal node As LidorSystems.IntegralUI.Lists.TreeNode)

' Hold te number of unchecked and visible nodes

Dim numUnchecked As Integer = 0

Dim numVisible As Integer = 0

 

' Let presume that by default that node is checked

Dim state As CheckState = CheckState.Checked

 

' Get the parent node

Dim parentNode As LidorSystems.IntegralUI.Lists.TreeNode = node.Parent

While parentNode IsNot Nothing

numUnchecked = 0

numVisible = 0

 

state = CheckState.Checked

For Each childNode As LidorSystems.IntegralUI.Lists.TreeNode In parentNode.Nodes

If childNode.Visible Then

numVisible += 1

' If there is at least one Indeterminate node, exit the loop.

' The state for the parent node will be also Indeterminate

If childNode.CheckState = CheckState.Indeterminate Then

state = CheckState.Indeterminate

Exit For

' Count the unchecked nodes

ElseIf childNode.CheckState = CheckState.Unchecked Then

numUnchecked += 1

End If

End If

Next

 

If numVisible > 0 Then

' If there are no unchecked nodes and there is at least one indeterminate node,

' that means that all child nodes are checked. So, the parent node will also be Checked

If numUnchecked = 0 AndAlso state <> CheckState.Indeterminate Then

state = CheckState.Checked

' If number of visible and unchecked nodes are equal, then parent node will be Unchecked

ElseIf numUnchecked = numVisible Then

state = CheckState.Unchecked

Else

' In any other case, then parent node will be Indeterminate

state = CheckState.Indeterminate

End If

Else

' If there are no visible nodes, the parent node will be unchecked

state = CheckState.Unchecked

End If

 

' Use this method to change the CheckState of the node,

' without triggerring the BeforeCheck and AfterCheck events

' this.treeView1.ChangeCheckState(parentNode, state);

parentNode.CheckState = state

 

' Repeat the whole cycle for other parent nodes

parentNode = parentNode.Parent

End While

End Sub

A complete sample project in C# .NET and VB .NET, showing how to create nodes with tri-state checkboxes in TreeView, is available for download from here: TreeView .NET - Three State Checkboxes

Did you Like this Article?


Enter your e-mail address below and you will receive latest articles as well as news on upcoming events and special offers.