TreeView for WinForms | ComponentOne
In This Topic
    Custom Nodes
    In This Topic

    TreeView allows creating and displaying custom nodes in place of the default nodes. It is possible to add custom properties and show various customizations, for instance, including, scaling, and aligning images, displaying borders, customizing font styles and colors, and changing dimensions etc. To set custom nodes in TreeView, set the CustomContentPresenter property of C1TreeColumn.

    Note: The SetStyle method of the CustomContentPresenter class supports gradients while using custom nodes in C1TreeView control with C1.Win.C1Themes.

    The following image displays custom nodes in TreeView.

    Custom Nodes

    To create custom nodes in TreeView, create custom classes to define properties and methods that apply to custom nodes and override the default ones. After creating custom classes, initialize their instances and set custom nodes using the CustomContentPresenter property.

    The following code snippets show how to create custom classes to define main elements for custom nodes.

    Public Class CategoryCustomNode
        Inherits CustomContentPresenter
        ' level 0
        Private _name As TextElement
        Private _description As TextElement
        Private _img As ImageElement
        Private _rw As RowPanel
        ' level 1
        Private _product As TextElement
    
        Public Sub New()
            ' level 0
            ' init text elements
            ' name
            _name = New TextElement()
            _name.Style = New Style()
            ' description
            _description = New TextElement()
            _description.Style = New Style()
            _description.Width = 120
            ' init image element
            _img = New ImageElement()
            _img.Style = New Style()
            _img.Size = New Size(70, 50)
            ' init a grid for text elements
            Dim cp = New ColumnPanel()
            cp.Children.Add(_name)
            cp.Children.Add(_description)
            ' init panel for image
            _rw = New RowPanel()
            _rw.Children.Add(cp)
            _rw.Children.Add(_img)
            _rw.Style = New Style()
            _rw.Style.VerticalAlignment = Alignment.Center
            ' level 1
            _product = New TextElement()
            _product.Style = New Style()
        End Sub
    
        Public Overrides ReadOnly Property ToolTipText() As String
            Get
                Return _name.Text
            End Get
        End Property
    
        Public Overrides Sub SetStyle(styles As TreeNodeCellStyles)
            ' level 0
            ' name 
            _name.Style.Margins = New Thickness(1)
            _name.Style.Font = New Font("Calibri", 10, FontStyle.Bold)
            ' description
            _description.Style.Margins = New Thickness(1)
            _description.Style.Font = New Font("Calibri", 9, FontStyle.Italic)
            _description.Style.WordWrap = True
            ' img
            _img.Style.ImageScaling = ImageScaling.Scale
            _img.Style.ImageAlignment = ImageAlignment.CenterCenter
            ' level 1
            _product.Style.Font = New Font("Calibri", 10, FontStyle.Bold)
            _product.Style.Margins = New Thickness(2)
            _product.Style.HorizontalAlignment = Alignment.Center
            _product.Style.VerticalAlignment = Alignment.Center
        End Sub
    
        Public Overrides Sub SetValue(value As Object)
            If Node.Level = 0 Then
                Dim row = DirectCast(Node.GetValue(), DataSet1.CategoriesRow)
                _name.Text = row.CategoryName
                _description.Text = row.Description
                Dim converter = New ImageConverter()
                If _img.Image IsNot Nothing Then
                    _img.Image.Dispose()
                    _img.Image = Nothing
                End If
                _img.Image = DirectCast(converter.ConvertFrom(row.Picture), Image)
                ' set root panel
                Child = _rw
            Else
                _product.Text = value.ToString()
                ' set root element
                Child = _product
            End If
        End Sub
    End Class
    
    Public Class ProductCustomNode
        Inherits CustomContentPresenter
        ' level 0
        Private _count As TextElement
        ' level 1
        Private _quantityPerUnit As TextElement
        Private _unitPrice As TextElement
        Private _unitInStock As TextElement
        Private _unitsOnOrder As TextElement
        Private _reorderLevel As TextElement
        Private _gp As GridPanel
        Private _eStyle As Style
    
        Public Sub New()
            ' level 0
            ' count in category
            _count = New TextElement()
            _count.Style = New Style()
            _count.Style.Margins = New Thickness(2)
            ' level 1
            ' lable style
            Dim lStyle = New Style()
            lStyle.HorizontalAlignment = Alignment.Far
            lStyle.Margins = New Thickness(1)
            lStyle.Font = New Font("Calibri", 9, FontStyle.Regular)
            ' elements style
            _eStyle = New Style()
            _eStyle.Margins = New Thickness(1)
            _eStyle.Font = New Font("Calibri", 9, FontStyle.Regular)
            ' init elements
            _quantityPerUnit = New TextElement(_eStyle.Clone())
            _unitPrice = New TextElement(_eStyle.Clone())
            _unitInStock = New TextElement(_eStyle.Clone())
            _unitsOnOrder = New TextElement(_eStyle.Clone())
            _reorderLevel = New TextElement(_eStyle.Clone())
            ' init a grid for text elements
            _gp = New GridPanel()
            _gp.Columns.Add()
            ' labels
            _gp.Columns(0).Width = 100
            _gp.Columns.Add()
            ' text
            _gp.Columns(1).Width = 120
    
            _gp.Rows.Add()
            ' ReorderLevel
            _gp(0, 0).Element = New TextElement(lStyle, "Reorder level:")
            _gp(0, 1).Element = _reorderLevel
            _gp.Rows.Add()
            ' UnitPrice
            _gp(1, 0).Element = New TextElement(lStyle, "Unit price:")
            _gp(1, 1).Element = _unitPrice
            _gp.Rows.Add()
            ' QuantityPerUnit
            _gp(2, 0).Element = New TextElement(lStyle, "Quantity per unit:")
            _gp(2, 1).Element = _quantityPerUnit
    
            _gp.Columns.Add()
            ' labels
            _gp.Columns(2).Width = 100
            _gp.Columns.Add()
            ' text
            ' UnitsInStock
            _gp(0, 2).Element = New TextElement(lStyle, "Units in stock:")
            _gp(0, 3).Element = _unitInStock
            ' UnitsOnOrder
            _gp(1, 2).Element = New TextElement(lStyle, "Units on order:")
    
            _gp(1, 3).Element = _unitsOnOrder
        End Sub
    
        Public Overrides ReadOnly Property ToolTipText() As String
            Get
                Return String.Empty
            End Get
        End Property
    
        Public Overrides Sub SetStyle(styles As TreeNodeCellStyles)
            ' level 0
            _count.Style.HorizontalAlignment = Alignment.Center
            _count.Style.VerticalAlignment = Alignment.Center
            _count.Style.Font = New Font("Calibri", 11, FontStyle.Bold)
            ' level 1
            _unitPrice.Style.Font = New Font(_eStyle.Font, FontStyle.Bold)
            If _unitInStock.Text = "0" Then
                _unitInStock.Style.ForeColor = Color.Red
                _unitInStock.Style.Font = New Font(_eStyle.Font, FontStyle.Bold)
            End If
            If _unitsOnOrder.Text = "0" Then
                _unitsOnOrder.Style.ForeColor = Color.Red
                _unitsOnOrder.Style.Font = New Font(_eStyle.Font, FontStyle.Bold)
            End If
        End Sub
    
        Public Overrides Sub SetValue(value As Object)
            If Node.Level = 0 Then
                Dim count = If(Node.HasChildren, Node.Nodes.Count, 0)
                _count.Text = count.ToString()
                Child = _count
            Else
                Dim row = DirectCast(Node.GetValue(), DataSet1.ProductsRow)
                _quantityPerUnit.Text = row.QuantityPerUnit
                _unitPrice.Text = row.UnitPrice.ToString("C")
                _unitInStock.Text = row.UnitsInStock.ToString()
                _unitsOnOrder.Text = row.UnitsOnOrder.ToString()
                _reorderLevel.Text = row.ReorderLevel.ToString()
                Child = _gp
            End If
        End Sub
    End Class
    
    public class CategoryCustomNode : CustomContentPresenter
    {
        // level 0
        private TextElement _name;
        private TextElement _description;
        private ImageElement _img;
        private RowPanel _rw;
        // level 1
        private TextElement _product;
    
        public CategoryCustomNode()
        {
            // level 0
            // init text elements
            // name
            _name = new TextElement();
            _name.Style = new Style();                    
            // description
            _description = new TextElement();
            _description.Style = new Style();
            _description.Width = 120;
            // init image element
            _img = new ImageElement();
            _img.Style = new Style();
            _img.Size = new Size(70, 50);            
            // init a grid for text elements
            var cp = new ColumnPanel();
            cp.Children.Add(_name);
            cp.Children.Add(_description);
            // init panel for image
            _rw = new RowPanel();
            _rw.Children.Add(cp);
            _rw.Children.Add(_img);
            _rw.Style = new Style();
            _rw.Style.VerticalAlignment = Alignment.Center;
            // level 1
            _product = new TextElement();
            _product.Style = new Style();
        }
    
        public override string ToolTipText
        {
            get
            {
                return _name.Text;
            }
        }
    
        public override void SetStyle(TreeNodeCellStyles styles)
        {
            // level 0
            // name 
            _name.Style.Margins = new Thickness(1);
            _name.Style.Font = new Font("Calibri", 10, FontStyle.Bold);
            // description
            _description.Style.Margins = new Thickness(1);
            _description.Style.Font = new Font("Calibri", 9, FontStyle.Italic);
            _description.Style.WordWrap = true;
            // img
            _img.Style.ImageScaling = ImageScaling.Scale;
            _img.Style.ImageAlignment = ImageAlignment.CenterCenter;    
            // level 1
            _product.Style.Font = new Font("Calibri", 10, FontStyle.Bold);
            _product.Style.Margins = new Thickness(2);
            _product.Style.HorizontalAlignment = Alignment.Center;
            _product.Style.VerticalAlignment = Alignment.Center;
        }
    
        public override void SetValue(object value)
        {
            if (Node.Level == 0)
            {
                var row = (DataSet1.CategoriesRow)Node.GetValue();
                _name.Text = row.CategoryName;
                _description.Text = row.Description;
                var converter = new ImageConverter();
                if (_img.Image != null)
                {
                    _img.Image.Dispose();
                    _img.Image = null;
                }
                _img.Image = (Image)converter.ConvertFrom(row.Picture);
                // set root panel
                Child = _rw;
            }
            else
            {
                _product.Text = value.ToString();
                // set root element
                Child = _product;
            }
        }
    }
    
    public class ProductCustomNode : CustomContentPresenter
    {
        // level 0
        private TextElement _count;
        // level 1
        private TextElement _quantityPerUnit;
        private TextElement _unitPrice;
        private TextElement _unitInStock;
        private TextElement _unitsOnOrder;
        private TextElement _reorderLevel;
        private GridPanel _gp;
        private Style _eStyle;
    
        public ProductCustomNode()
        {
            // level 0
            // count in category
            _count = new TextElement();
            _count.Style = new Style();
            _count.Style.Margins = new Thickness(2);
            // level 1
            // lable style
            var lStyle = new Style();
            lStyle.HorizontalAlignment = Alignment.Far;
            lStyle.Margins = new Thickness(1);
            lStyle.Font = new Font("Calibri", 9, FontStyle.Regular);
            // elements style
            _eStyle = new Style();
            _eStyle.Margins = new Thickness(1);
            _eStyle.Font = new Font("Calibri", 9, FontStyle.Regular);
            // init elements
            _quantityPerUnit = new TextElement(_eStyle.Clone());
            _unitPrice = new TextElement(_eStyle.Clone());
            _unitInStock = new TextElement(_eStyle.Clone());
            _unitsOnOrder = new TextElement(_eStyle.Clone());
            _reorderLevel = new TextElement(_eStyle.Clone());
            // init a grid for text elements
            _gp = new GridPanel();
            _gp.Columns.Add(); // labels
            _gp.Columns[0].Width = 100;
            _gp.Columns.Add(); // text
            _gp.Columns[1].Width = 120;
    
            _gp.Rows.Add(); // ReorderLevel
            _gp[0, 0].Element = new TextElement(lStyle, "Reorder level:");
            _gp[0, 1].Element = _reorderLevel;
            _gp.Rows.Add(); // UnitPrice
            _gp[1, 0].Element = new TextElement(lStyle, "Unit price:");
            _gp[1, 1].Element = _unitPrice;
            _gp.Rows.Add(); // QuantityPerUnit
            _gp[2, 0].Element = new TextElement(lStyle, "Quantity per unit:");
            _gp[2, 1].Element = _quantityPerUnit;                        
    
            _gp.Columns.Add(); // labels
            _gp.Columns[2].Width = 100;
            _gp.Columns.Add(); // text
            // UnitsInStock
            _gp[0, 2].Element = new TextElement(lStyle, "Units in stock:");
            _gp[0, 3].Element = _unitInStock;
            // UnitsOnOrder
            _gp[1, 2].Element = new TextElement(lStyle, "Units on order:");
            _gp[1, 3].Element = _unitsOnOrder;
    
        }
    
        public override string ToolTipText
        {
            get
            {
                return string.Empty; ;
            }
        }
    
        public override void SetStyle(TreeNodeCellStyles styles)
        {
            // level 0
            _count.Style.HorizontalAlignment = Alignment.Center;
            _count.Style.VerticalAlignment = Alignment.Center;
            _count.Style.Font = new Font("Calibri", 11, FontStyle.Bold);
            // level 1
            _unitPrice.Style.Font = new Font(_eStyle.Font, FontStyle.Bold);
            if (_unitInStock.Text == "0")
            {
                _unitInStock.Style.ForeColor = Color.Red;
                _unitInStock.Style.Font = new Font(_eStyle.Font, FontStyle.Bold);
            }
            if (_unitsOnOrder.Text == "0")
            {
                _unitsOnOrder.Style.ForeColor = Color.Red;
                _unitsOnOrder.Style.Font = new Font(_eStyle.Font, FontStyle.Bold);
            }
        }
    
        public override void SetValue(object value)
        {
            if (Node.Level == 0)
            {
                var count = Node.HasChildren ? Node.Nodes.Count : 0;
                _count.Text = count.ToString();
                Child = _count;
            }
            else
            {
                var row = (DataSet1.ProductsRow)Node.GetValue();
                _quantityPerUnit.Text = row.QuantityPerUnit;
                _unitPrice.Text = row.UnitPrice.ToString("C");                
                _unitInStock.Text = row.UnitsInStock.ToString();
                _unitsOnOrder.Text = row.UnitsOnOrder.ToString();
                _reorderLevel.Text = row.ReorderLevel.ToString();
                Child = _gp;
            }
        }
    }
    

    The following code snippet shows how to set custom nodes using the CustomContentPresenter property.

    ' set custom nodes
    C1TreeView1.Columns(0).CustomContentPresenter = New CategoryCustomNode()
    C1TreeView1.Columns(1).CustomContentPresenter = New ProductCustomNode()
    
    // set custom nodes
    c1TreeView1.Columns[0].CustomContentPresenter = new CategoryCustomNode();
    c1TreeView1.Columns[1].CustomContentPresenter = new ProductCustomNode();
    

    Using Checkboxes

    By default, TreeView does not display check boxes beside nodes. In order to display check boxes beside nodes in TreeView, set the CheckBoxes property of the C1TreeView class to True.

    The following code snippet sets the CheckBoxes property.

    ' set the CheckBoxes property to enable checkboxes in TreeView
    C1TreeView1.CheckBoxes = True
    
    // set the CheckBoxes property to enable checkboxes in TreeView
    c1TreeView1.CheckBoxes = true;
    

    Using check box in TreeView

    The check box next to a node can be checked by setting the Checked property of C1TreeNode to True. You can also alter the state of the check box of a node by setting the CheckState property of C1TreeNode to any of the following values from the CheckState enumeration of System.Windows.Forms: Checked, Indeterminate, and Unchecked.

    In addition, you can change the state of the check box of a node by using the Check or the Uncheck method of C1TreeNode, respectively. These methods accept a parameter allChildrens of the Boolean type. The parameter allChildrens determines whether the check boxes of all child nodes within a node will be checked or unchecked. C1TreeView provides the CheckAll or the UncheckAll method using which you can check or uncheck all the check boxes beside the nodes. Moreover, using these methods, you can check nodes recursively in which if a parent node is checked, all the child nodes under it are recursively checked.

    See the following code snippet for reference.

    ' set the parent nodes to the Checked state
    C1TreeView1.Nodes(0).CheckState = CheckState.Checked
    C1TreeView1.Nodes(1).CheckState = CheckState.Checked
    
    ' set the child nodes to the Checked state
    parentNode1.Nodes(1).Check()
    parentNode1.Nodes(4).Check()
    parentNode2.Nodes(2).Check()
    parentNode2.Nodes(2).CheckState = CheckState.Checked
    
    // set the parent nodes to the Checked state
    c1TreeView1.Nodes[0].CheckState = CheckState.Checked;
    c1TreeView1.Nodes[1].CheckState = CheckState.Checked;
    
    // set the child nodes to the Checked state
    parentNode1.Nodes[1].Check();
    parentNode1.Nodes[4].Check();
    parentNode2.Nodes[2].Check();
    parentNode2.Nodes[2].CheckState = CheckState.Checked;
    

    Using check box in TreeView

    Custom Button Images for Nodes

    TreeView allows you to easily display custom button images for nodes by using an image list.

    Create an instance of the Systems.Windows.Forms.ImageList class and add images to the list by using the Add method with the Images collection of the list. Set this instance as the image list of TreeView by using the ImageList property of the C1TreeView class.

    To access the collection of images for a particular node, you need to use the Images property of C1TreeNode. And to add a specific image from the image list to a specific node, add the index of the image by using the Add method of System.Collections.ObjectModel with the Images property of C1TreeNode.

    To see the implementation, refer to the following code snippets.

    ' create an instance of ImageList
    Dim imageList As New ImageList()
    
    ' add images to the image list
    imageList.Images.Add(Image.FromFile("C:\Resources\1.png"))
    imageList.Images.Add(Image.FromFile("C:\Resources\2.png"))
    imageList.Images.Add(Image.FromFile("C:\Resources\3.png"))
    
    ' set the image list instance as the TreeView image list
    C1TreeView1.ImageList = imageList
    
    ' specify image indices for nodes
    C1TreeView1.Nodes(0).Images.Add(0)
    C1TreeView1.Nodes(1).Images.Add(1)
    C1TreeView1.Nodes(2).Images.Add(2)
    
    // create an instance of ImageList
    ImageList imageList = new ImageList();
    
    // add images to the image list
    imageList.Images.Add(Image.FromFile("C:\\Resources\\1.png"));
    imageList.Images.Add(Image.FromFile("C:\\Resources\\2.png"));
    imageList.Images.Add(Image.FromFile("C:\\Resources\\3.png"));
    
    // set the image list instance as the TreeView image list
    c1TreeView1.ImageList = imageList;
    
    // specify image indices for nodes
    c1TreeView1.Nodes[0].Images.Add(0);
    c1TreeView1.Nodes[1].Images.Add(1);
    c1TreeView1.Nodes[2].Images.Add(2);
    

    Custom images for nodes

    Icons for Expand Button and Checkbox

    In TreeView, you can customize the way icons appear for expand buttons and check boxes.

    To customize the icons for expand buttons, you need to set the ExpandButtonStyle property provided by the TreeViewStyles class. The property accepts values from the ExpandButtonStyle enumeration. By using the values, you can set any of standard System, VS2015, or Windows10 views for the expand buttons. To customize the icons for check boxes, set the CheckBoxStyle property of TreeViewStyles, which accepts values from the CheckBoxStyle enumeration. Using those values, you can set any of the standard System, MS Office, or Windows10 views for the check boxes.

    Notice that you can use ExpandButtonStyle and CheckBoxStyle properties only after accessing TreeView styles by using the Styles property of C1TreeView.

    The following code snippets demonstrate the implementation.

    ' set the CheckBoxStyle property
    C1TreeView1.Styles.CheckBoxStyle = C1.Win.TreeView.CheckBoxStyle.Windows10
    
    ' set the ExpandButtonStyle property
    C1TreeView1.Styles.ExpandButtonStyle = C1.Win.TreeView.ExpandButtonStyle.Windows10
    
    // set the CheckBoxStyle property
    c1TreeView1.Styles.CheckBoxStyle = C1.Win.TreeView.CheckBoxStyle.Windows10;
    
    // set the ExpandButtonStyle property
    c1TreeView1.Styles.ExpandButtonStyle = C1.Win.TreeView.ExpandButtonStyle.Windows10;
    

    Custom icons for exapnd button and checkboxes

    Note: The latest WinForms .NET Edition does not include rich design-time support yet. We will enhance it in future releases.