New to Telerik UI for WinForms? Download free 30-day trial

Custom Nodes

With RadTreeView you can create custom nodes and display them instead of the default ones. This can be done by creating a custom TreeNodeElement, which will replace the default one in the CreateNodeElement event handler. This article demonstrates how this approach can be implemented.

WinForms RadTreeView Custom Nodes

To create this example you can first prepare a project by following the steps in this article

1. First we can create a custom TreeNodeContentElement class which contains the main elements for the custom node. These elements are created and initialized in the CreateChildElements method. Also the Synchronize method is overridden for setting the elements properties in accordance with the corresponding data:


class CustomContentElement : TreeNodeContentElement
{
    StackLayoutElement nodeContentContainer;
    LinePrimitive lineElement;
    LightVisualElement textElement;
    RadButtonElement buttonElement;

    protected override Type ThemeEffectiveType
    {
        get
        {
            return typeof(TreeNodeContentElement);
        }
    }
    protected override void InitializeFields()
    {
        base.InitializeFields();
        this.DrawBorder = true;
        this.NumberOfColors = 2;
        this.GradientStyle = GradientStyles.Linear;
        this.Margin = new Padding(5, 5, 5, 5);
        this.Shape = new RoundRectShape(2);
        this.StretchHorizontally = true;
    }
    public override void Synchronize()
    {
        this.DrawFill = true;

        TreeNodeElement treeNodeElement = this.NodeElement;
        RadTreeNode node = treeNodeElement.Data;
        DataRowView rowView = (DataRowView)node.DataBoundItem;

        if (node.Level == 0)
        {
            this.textElement.Text = "" + rowView["ArtistName"];
            if (node.Expanded == false)
            {
                buttonElement.Text = "Show Albums";
            }
            else
            {
                buttonElement.Text = "Hide Albums";
            }

            this.BorderColor = Color.FromArgb(110, 153, 210);
            this.BackColor = Color.FromArgb(174, 190, 217);
            this.BackColor2 = Color.FromArgb(168, 183, 210);
        }
        else if (node.Level == 1)
        {
            this.textElement.Text = "" + rowView["AlbumName"];
            this.buttonElement.Text = "Play Album";

            this.BorderColor = Color.FromArgb(210, 153, 210);
            this.BackColor = Color.FromArgb(74, 190, 217);
            this.BackColor2 = Color.FromArgb(50, 150, 190);
        }
        else
        {
            this.textElement.Text = "" + rowView["SongName"];
            this.buttonElement.Text = "Play Song";

            this.BorderColor = Color.FromArgb(110, 153, 110);
            this.BackColor = Color.FromArgb(234, 190, 117);
            this.BackColor2 = Color.FromArgb(208, 183, 110);
        }
    }

    protected override void CreateChildElements()
    {
        nodeContentContainer = new StackLayoutElement();
        nodeContentContainer.Orientation = Orientation.Vertical;
        nodeContentContainer.StretchHorizontally = true;
        nodeContentContainer.StretchVertically = false;

        textElement = new LightVisualElement();
        textElement.ShouldHandleMouseInput = false;
        textElement.NotifyParentOnMouseInput = true;
        textElement.StretchVertically = false;
        this.nodeContentContainer.Children.Add(textElement);

        lineElement = new LinePrimitive();
        lineElement.BackColor = Color.Black;
        lineElement.Margin = new Padding(10, 0, 10, 0);
        lineElement.StretchVertically = false;
        this.nodeContentContainer.Children.Add(lineElement);

        buttonElement = new RadButtonElement();
        buttonElement.Margin = new Padding(20, 3, 20, 3);
        buttonElement.Click += buttonElement_Click;
        buttonElement.StretchVertically = false;
        this.nodeContentContainer.Children.Add(buttonElement);

        this.Children.Add(nodeContentContainer);
    }

    void buttonElement_Click(object sender, EventArgs e)
    {
        TreeNodeElement treeNodeElement = this.NodeElement;
        RadTreeNode node = treeNodeElement.Data;
        if (node.Level == 0)
        {
            if (node.Expanded == true)
            {
                node.Collapse();
                buttonElement.Text = "Show Albums";
            }
            else
            {
                node.Expand();
                buttonElement.Text = "Hide Albums";
            }
        }
    }
}

Class CustomContentElement
    Inherits TreeNodeContentElement
    Private nodeContentContainer As StackLayoutElement
    Private lineElement As LinePrimitive
    Private textElement As LightVisualElement
    Private buttonElement As RadButtonElement
    Protected Overrides ReadOnly Property ThemeEffectiveType() As Type
        Get
            Return GetType(TreeNodeContentElement)
        End Get
    End Property
    Protected Overrides Sub InitializeFields()
        MyBase.InitializeFields()
        Me.DrawBorder = True
        Me.NumberOfColors = 2
        Me.GradientStyle = GradientStyles.Linear
        Me.Margin = New Padding(5, 5, 5, 5)
        Me.Shape = New RoundRectShape(2)
        Me.StretchHorizontally = True
    End Sub
    Public Overrides Sub Synchronize()
        Me.DrawFill = True
        Dim treeNodeElement As TreeNodeElement = Me.NodeElement
        Dim node As RadTreeNode = treeNodeElement.Data
        Dim rowView As DataRowView = DirectCast(node.DataBoundItem, DataRowView)
        If node.Level = 0 Then
            Me.textElement.Text = rowView("ArtistName")
            If node.Expanded = False Then
                buttonElement.Text = "Show Albums"
            Else
                buttonElement.Text = "Hide Albums"
            End If
            Me.BorderColor = Color.FromArgb(110, 153, 210)
            Me.BackColor = Color.FromArgb(174, 190, 217)
            Me.BackColor2 = Color.FromArgb(168, 183, 210)
        ElseIf node.Level = 1 Then
            Me.textElement.Text = rowView("AlbumName")
            Me.buttonElement.Text = "Play Album"
            Me.BorderColor = Color.FromArgb(210, 153, 210)
            Me.BackColor = Color.FromArgb(74, 190, 217)
            Me.BackColor2 = Color.FromArgb(50, 150, 190)
        Else
            Me.textElement.Text = rowView("SongName")
            Me.buttonElement.Text = "Play Song"
            Me.BorderColor = Color.FromArgb(110, 153, 110)
            Me.BackColor = Color.FromArgb(234, 190, 117)
            Me.BackColor2 = Color.FromArgb(208, 183, 110)
        End If
    End Sub
    Protected Overrides Sub CreateChildElements()
        nodeContentContainer = New StackLayoutElement()
        nodeContentContainer.Orientation = Orientation.Vertical
        nodeContentContainer.StretchHorizontally = True
        nodeContentContainer.StretchVertically = False
        textElement = New LightVisualElement()
        textElement.ShouldHandleMouseInput = False
        textElement.NotifyParentOnMouseInput = True
        textElement.StretchVertically = False
        Me.nodeContentContainer.Children.Add(textElement)
        lineElement = New LinePrimitive()
        lineElement.BackColor = Color.Black
        lineElement.Margin = New Padding(10, 0, 10, 0)
        lineElement.StretchVertically = False
        Me.nodeContentContainer.Children.Add(lineElement)
        buttonElement = New RadButtonElement()
        buttonElement.Margin = New Padding(20, 3, 20, 3)
        AddHandler buttonElement.Click, AddressOf buttonElement_Click
        buttonElement.StretchVertically = False
        Me.nodeContentContainer.Children.Add(buttonElement)
        Me.Children.Add(nodeContentContainer)
        Me.Shape = New RoundRectShape(2)
        Me.StretchHorizontally = True
    End Sub
    Private Sub buttonElement_Click(sender As Object, e As EventArgs)
        Dim treeNodeElement As TreeNodeElement = Me.NodeElement
        Dim node As RadTreeNode = treeNodeElement.Data
        If node.Level = 0 Then
            If node.Expanded = True Then
                node.Collapse()
                buttonElement.Text = "Show Albums"
            Else
                node.Expand()
                buttonElement.Text = "Hide Albums"
            End If
        End If
    End Sub
End Class

2. Now we can use the already created CustomContentElement and create a custom TreeNodeElement class. Also here the Synchronize method is overridden in order to set the picture of the node:


public class CustomTreeNodeElement : TreeNodeElement
{

    protected override TreeNodeContentElement CreateContentElement()
    {
        return new CustomContentElement();
    }
    public override void Synchronize()
    {
        base.Synchronize();

        RadTreeNode node = this.Data;
        DataRowView rowView = (DataRowView)node.DataBoundItem;
        if (node.Level != 2)
        {
            this.ImageElement.Image = ImageHelper.GetImageFromBytes((byte[])rowView["Image"]).GetThumbnailImage(50, 50, null, IntPtr.Zero);
        }
        else
        {
            this.ImageElement.Image = Resources.the_music_icon.GetThumbnailImage(50, 50, null, IntPtr.Zero);
        }
    }

    protected override Type ThemeEffectiveType
    {
        get
        {
            return typeof(TreeNodeElement);
        }
    }
}

Public Class CustomTreeNodeElement
    Inherits TreeNodeElement
    Protected Overrides Function CreateContentElement() As TreeNodeContentElement
        Return New CustomContentElement()
    End Function
    Public Overrides Sub Synchronize()
        MyBase.Synchronize()
        Dim node As RadTreeNode = Me.Data
        Dim rowView As DataRowView = DirectCast(node.DataBoundItem, DataRowView)
        If node.Level <> 2 Then
            Me.ImageElement.Image = ImageHelper.GetImageFromBytes(DirectCast(rowView("Image"), Byte())).GetThumbnailImage(50, 50, Nothing, IntPtr.Zero)
        Else
            Me.ImageElement.Image = My.Resources.the_music_icon.GetThumbnailImage(50, 50, Nothing, IntPtr.Zero)
        End If
    End Sub
    Protected Overrides ReadOnly Property ThemeEffectiveType() As Type
        Get
            Return GetType(TreeNodeElement)
        End Get
    End Property
End Class

3. Finally, we can add a little bit more customization by setting some of the RadTreeView properties in the form's Load event handler. And also we need to subscribe to the CreateNodeElement event in order to use the newly created custom nodes:


private void CustomNodes_Load(object sender, EventArgs e)
{
    // TODO: This line of code loads data into the 'musicCollectionDataSet.Artists' table. You can move, or remove it, as needed.
    this.artistsTableAdapter.Fill(this.musicCollectionDataSet.Artists);
    // TODO: This line of code loads data into the 'musicCollectionDataSet.Albums' table. You can move, or remove it, as needed.
    this.albumsTableAdapter.Fill(this.musicCollectionDataSet.Albums);
    // TODO: This line of code loads data into the 'musicCollectionDataSet.Songs' table. You can move, or remove it, as needed.
    this.songsTableAdapter.Fill(this.musicCollectionDataSet.Songs);

    this.radTreeView1.DataSource = this.artistsBindingSource;
    this.radTreeView1.DisplayMember = "ArtistName";
    this.radTreeView1.ValueMember = "ArtistID";
    this.radTreeView1.RelationBindings.Add(new RelationBinding(this.albumsBindingSource, "AlbumName", "ArtistID", "ArtistID", "AlbumID"));
    this.radTreeView1.RelationBindings.Add(new RelationBinding(this.songsBindingSource, "SongName", "AlbumID", "AlbumID", "SongID"));
    this.radTreeView1.TreeViewElement.CreateNodeElement += TreeViewElement_CreateNodeElement;
    this.radTreeView1.TreeViewElement.AutoSizeItems = true;
    this.radTreeView1.ShowRootLines = false;
    this.radTreeView1.FullRowSelect = false;
    this.radTreeView1.ShowLines = true;
    this.radTreeView1.LineStyle = TreeLineStyle.Solid;
    this.radTreeView1.LineColor = Color.FromArgb(110, 153, 210);
    this.radTreeView1.TreeIndent = 50;
    radTreeView1.TreeViewElement.CollapseImage = Resources.toggle_expand_basic_blue.GetThumbnailImage(20, 20, null, IntPtr.Zero);
    radTreeView1.TreeViewElement.ExpandImage = Resources.toggle_collapse_basic_blue.GetThumbnailImage(20, 20, null, IntPtr.Zero);
    this.radTreeView1.ExpandAll();
}

void TreeViewElement_CreateNodeElement(object sender, Telerik.WinControls.UI.CreateTreeNodeElementEventArgs e)
{
    e.NodeElement = new CustomTreeNodeElement();
}

Private Sub CustomNodes_Load(sender As Object, e As EventArgs) Handles Me.Load
    Me.ArtistsTableAdapter.Fill(Me.MusicCollectionDataSet.Artists)
    'TODO: This line of code loads data into the 'MusicCollectionDataSet.Songs' table. You can move, or remove it, as needed.
    Me.SongsTableAdapter.Fill(Me.MusicCollectionDataSet.Songs)
    'TODO: This line of code loads data into the 'MusicCollectionDataSet.Albums' table. You can move, or remove it, as needed.
    Me.AlbumsTableAdapter.Fill(Me.MusicCollectionDataSet.Albums)
    'TODO: This line of code loads data into the 'MusicCollectionDataSet.Artists' table. You can move, or remove it, as needed.
    Me.RadTreeView1.DataSource = Me.ArtistsBindingSource
    Me.RadTreeView1.DisplayMember = "ArtistName"
    Me.RadTreeView1.ValueMember = "ArtistID"
    Me.RadTreeView1.RelationBindings.Add(New RelationBinding(Me.AlbumsBindingSource, "AlbumName", "ArtistID", "ArtistID", "AlbumID"))
    Me.RadTreeView1.RelationBindings.Add(New RelationBinding(Me.SongsBindingSource, "SongName", "AlbumID", "AlbumID", "SongID"))
    AddHandler Me.RadTreeView1.TreeViewElement.CreateNodeElement, AddressOf TreeViewElement_CreateNodeElement
    Me.RadTreeView1.TreeViewElement.AutoSizeItems = True
    Me.RadTreeView1.ShowRootLines = False
    Me.RadTreeView1.TreeIndent = 50
    Me.RadTreeView1.FullRowSelect = False
    Me.RadTreeView1.ShowLines = True
    Me.RadTreeView1.LineStyle = TreeLineStyle.Solid
    Me.RadTreeView1.LineColor = Color.FromArgb(110, 153, 210)
    RadTreeView1.TreeViewElement.CollapseImage = My.Resources.toggle_expand_basic_blue.GetThumbnailImage(20, 20, Nothing, IntPtr.Zero)
    RadTreeView1.TreeViewElement.ExpandImage = My.Resources.toggle_collapse_basic_blue.GetThumbnailImage(20, 20, Nothing, IntPtr.Zero)
    Me.RadTreeView1.ExpandAll()
End Sub
Private Sub TreeViewElement_CreateNodeElement(sender As Object, e As Telerik.WinControls.UI.CreateTreeNodeElementEventArgs)
    e.NodeElement = New CustomTreeNodeElement()
End Sub

See Also

In this article