Click here to Skip to main content
Click here to Skip to main content

Tri-State TreeView Control for .NET 1.1

, 14 Dec 2007 CPOL
Rate this:
Please Sign up or sign in to vote.
Tri-state checkboxes, user-defined state images, disable checkboxes per node...

Screenshot -

Introduction

The TreeView control as implemented by Microsoft in the .NET 1.1 Framework does support checkboxes, but those checkboxes allow only two states: checked or unchecked.

This control is built on top of the TreeView control, and provides some additional functionality that might be useful.

  • Tri-state checkboxes, checked / unchecked / indeterminate state.
  • TriStateTreeView supports custom images for all three states. When not using custom images, default tri-state images are provided. Custom images are configured the same way as the "ImageIndex" and the "SelectedImageIndex" properties, so state images can be added to the ImageList bound to the TreeView using the ImageList property.
  • Checkboxes can be switched off on a per-node basis.
  • The TreeView recognizes two different types of TreeNodes: Containers and Items. They behave differently when child nodes are checked / unchecked.

Background

Some of this code, mostly the wndproc hooks, comes from another sample found on this site. It was a VB.NET sample developed by Carlos J. Quintero dealing with the node fonts: http://www.codeproject.com/KB/cpp/CustomDrawTreeview.aspx. I translated that sample and added my own stuff. Thanks Carlos for sharing your code with us.

Using the code

The sources contain two classes: TriStateTreeView and TriStateTreeNode.

The TriStateTreeNode class exposes an internal property, NodeLineType, which is read by the TriStateTreeView control when it is about to draw the node. When a checkbox has been disabled for a certain node, a dotted line should be drawn to replace that checkbox, in the way the original TreeView would do it.

Enum NodeLineType

The property NodeLineType returns a value of type NodeLineType, which can have three different values:

  • None - No line needs to be drawn
  • Straight - Only a straight line has to be drawn where normally a checkbox would be drawn
  • WithChildren - A straight line must be drawn, and a connecting line to the node's children
internal enum NodeLineType
{
    None,
    Straight,
    WithChildren
}

Class TriStateTreeView

The class TriStateTreeView has been derived from System.Windows.Forms.TreeView, and exposes the additional properties listed below:

  • UseCustomImages - Design or runtime editable. Determines if the TreeView draws the images configured in the ImageList (custom), or the default images.
  • CheckedImageIndex - Index of the image to display when the node is in the Checked state (UseCustomImages must be true).
  • UncheckedImageIndex - Index of the image to display when the node is in the Unchecked state (UseCustomImages must be true).
  • IndeterminateImageIndex - Index of the image to display when the node is in the Indeterminate state (UseCustomImages must be true).

The above four properties have all been placed in a single category in the property browser, named CheckState.

Class TriStateTreeNode

The class TriStateTreeNode has been derived from System.Windows.Forms.TreeNode, and exposes the extra functionality described below:

  • It hides the original Checked property, and returns true when its CheckState property is either Checked or Indeterminate. The property returns Unchecked when CheckState is Unchecked.
  • Additional read-only property CheckState which returns either Checked/Unchecked/Indeterminate depending on the current state.
  • Additional read-write property IsContainer which determines if a TreeNode behaves as a container or as an item.
  • Additional read-write property CheckboxVisible which determines if a node exposes a checkbox.
  • Internal property NodeLineType (see previous explanation).
  • Internal method SetCheckedState( CheckState value): Provides an interface for the TriStateTreeView class.

Sample code

private void ConfigureTreeView()
{
    TriStateTreeNode folderNode = null;

    TriStateTreeNode rootNode = 
      new TriStateTreeNode( "Home - \"CheckboxVisible = false\"." );
    rootNode.CheckboxVisible = false;
    rootNode.IsContainer = true;

    for( int i = 1; i < 4; i++ )
    {
        folderNode = new TriStateTreeNode( string.Format( "Foldernode {0}," + 
                         " can show 3 states, as shown here.", i), 0, 1 );
        folderNode.IsContainer = true;
        rootNode.Nodes.Add( folderNode );
    }

    folderNode = new TriStateTreeNode("Foldernode 4, " + 
                     "cannot be checked, as shown here.", 0, 1);
    folderNode.IsContainer = true;
    folderNode.CheckboxVisible = false;

    rootNode.Nodes.Add(folderNode);

    TriStateTreeNode firstFolder = rootNode.FirstNode as TriStateTreeNode;
    for(int i = 1; i < 3; i++)
    {
        TriStateTreeNode itemNode = 
          new TriStateTreeNode( string.Format( "Item node {0}", i ), 2, 2 );
        firstFolder.Nodes.Add( itemNode );
    }

    TriStateTreeNode secondFolder = firstFolder.NextNode as TriStateTreeNode;
    for(int i = 1; i < 3; i++)
    {
        TriStateTreeNode itemNode = 
          new TriStateTreeNode( string.Format( "Item node {0}", i ), 2, 2);
        secondFolder.Nodes.Add( itemNode );
    }

    TriStateTreeNode thirdFolder = secondFolder.NextNode as TriStateTreeNode;
    for(int i = 1; i < 3; i++)
    {
        TriStateTreeNode itemNode = 
          new TriStateTreeNode( string.Format( "Item node {0}", i ), 2, 2 );
        thirdFolder.Nodes.Add( itemNode );
    }

    TriStateTreeNode fourthFolder = folderNode;
    fourthFolder.CheckboxVisible = false;
    for(int i = 1; i < 3; i++)
    {
        TriStateTreeNode itemNode = 
          new TriStateTreeNode( string.Format( 
          "Item node {0} - no checkboxes", i ), 2, 2 );
        itemNode.CheckboxVisible = false;
        fourthFolder.Nodes.Add( itemNode );
    }

    this.triStateTreeView1.SuspendLayout();
    this.triStateTreeView1.Nodes.Add( rootNode );
    this.triStateTreeView1.ResumeLayout();

    secondFolder.FirstNode.Checked = true;
    thirdFolder.Checked = true;
}

Points of interest

There are still a couple of issues I want to fix, feedback about it will be appreciated.

Microsoft has a TreeNodeCollectionEditor which will let you construct a tree at design time. Normally, I think this editor is not likely to be used since most treeviews will show dynamic data which will almost never be pre-configured. However... the editor doesn't work with this treeview because it adds TreeNodes instead of TriStateTreeNodes, which disables the entire tri-state concept. I haven't quite figured out what to do about it.

I guess a solution to this problem should involve hiding the Nodes property from the TreeView control by adding our own Nodes property which is a TreeNodeCollection like collection class that stores TriStateTreeNodes. That, together with a custom TreeNodeCollectionEditor, should just about take care of the problem.

History

  • 14 December 2007 - First version.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Evert Timmer
Software Developer (Senior)
Netherlands Netherlands
No Biography provided

Comments and Discussions

 
QuestionTri-State TreeView Control for .NET 1.1 PinmemberDionly24-Jun-13 5:54 
Questioncan't use control Pinmembergladiator50200010-Feb-13 8:10 
Questionthanks your job and I chang some code to make it better Pinmembertokenian24-Dec-12 22:15 
QuestionMissing Implementations for Nodes and Associated Methods PinmemberAylwyn26-Dec-11 15:43 
GeneralMy vote of 5 PinmemberMember 369480730-Oct-11 23:42 
QuestionUse WndProc() Hook to create "invisible" TreeNodes - How? PinmemberElitetum2-Aug-11 1:01 
AnswerRe: Use WndProc() Hook to create "invisible" TreeNodes - How? PinmemberEvert Timmer2-Aug-11 1:50 
SuggestionHow to hide checkbox of the certain TreeNode in TreeView control PinmemberMember 14778530-Jun-11 17:12 
QuestionHow to change ForeColor property of extended treenode at runtime Pinmemberfarhaan8-Aug-10 20:07 
GeneralNode CheckState Pinmemberweepl40719-Nov-09 22:16 
GeneralTriStateTreeNode BackColor property PinmemberMember 195776514-Nov-08 1:04 
GeneralRe: TriStateTreeNode BackColor property PinmemberEvert Timmer14-Nov-08 22:18 
GeneralRe: TriStateTreeNode BackColor property Pinmemberlijiuning30-Nov-11 22:23 
GeneralError. Node image is not refreshed when change state from code Pinmembereyanson28-Oct-08 4:32 
GeneralRe: Error. Node image is not refreshed when change state from code PinmemberEvert Timmer14-Nov-08 22:19 
GeneralRe: Error. Node image is not refreshed when change state from code Pinmembersdasdasdagg22-Jul-13 19:24 
QuestionQuestion on intermediate state Pinmembernico.pyright29-Sep-08 12:32 
AnswerRe: Question on intermediate state Pinmember-camalot-9-Dec-08 3:32 
QuestionHow can I hide 2-nd icon i.e. folder_closed / folder_opened PinmemberMarek Zgadzaj27-May-08 3:39 
AnswerRe: How can I hide 2-nd icon i.e. folder_closed / folder_opened PinmemberDorsch11-Oct-09 9:31 
GeneralWorks for 2.0 as well!!!!!! PinmemberBrad Bruce14-Dec-07 4:09 
GeneralRe: Works for 2.0 as well!!!!!! PinmemberEvert Timmer14-Dec-07 4:45 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.141223.1 | Last Updated 14 Dec 2007
Article Copyright 2007 by Evert Timmer
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid