Populating a TreeView Control from a List

Posted Mon, Nov 9 2009 21:25 by Deborah Kurata

This post details first how to build a list containing the data to display in a WinForms TreeView control. Then it demonstrates how to use recursion to populate the TreeView control from the list.

[For information on populating a TreeView control from XML, see this link.]

First, create a class that will store the data for the TreeView.

In C#:

public class TreeViewItem
{
    public int ID { get; set; }
    public int ParentID { get; set; }
    public string Text { get; set; }
}

In VB:

Public Class TreeViewItem
    Public Id As Integer
    Public ParentId As Integer
    Public Text As String
End Class

The C# code uses auto-implemented properties to short-cut the code. The VB code is just me being lazy tonight. It is using Public fields instead of Public Properties as it should. (In VS 2010, VB will have auto—implemented properties as well.)

The class defines an Id associated with the item and a ParentId defining the Id of the parent item (that is the item under which this item will appear in the TreeView). It also has a Text property that contains the text of the TreeView node.

In the WinForm containing the TreeView control, add the code to build the list as shown below.

In C#:

List<TreeViewItem> treeViewList = new List<TreeViewItem>();

treeViewList.Add(new TreeViewItem() { 
          ParentID = 0, ID = 1, Text = "Parent node" });
treeViewList.Add(new TreeViewItem() { 
          ParentID = 1, ID = 2, Text = "First child node" });
treeViewList.Add(new TreeViewItem() { 
         ParentID = 1, ID = 3, Text = "Second child node" });
treeViewList.Add(new TreeViewItem() { 
         ParentID = 3, ID = 4, Text = "Child of second child node" });
treeViewList.Add(new TreeViewItem() { 
         ParentID = 3, ID = 5, Text = "Child of second child node" });

PopulateTreeView(0, null);

In VB:

Private treeViewList As New List(Of TreeViewItem)

treeViewList.Add(New TreeViewItem() With { _
        .ParentId = 0, .Id = 1, .Text = "Parent node"})
treeViewList.Add(New TreeViewItem() With { _
        .ParentId = 1, .Id = 2, .Text = "First child node"})
treeViewList.Add(New TreeViewItem() With { _
        .ParentId = 1, .Id = 3, .Text = "Second child node"})
treeViewList.Add(New TreeViewItem() With { _
        .ParentId = 3, .Id = 4, .Text = "Child of second child node"})
treeViewList.Add(New TreeViewItem() With { _
        .ParentId = 3, .Id = 5, .Text = "Child of second child node"})

PopulateTreeView(0, Nothing)

This code defines a generic List that contains the set of TreeViewItem instances. The Add method of the list sets the data into the list. It then calls the PopulateTreeView method (shown below).

The PopulateTreeView method uses recursion to populate the TreeView from the list.

In C#:

private void PopulateTreeView(int parentId, TreeNode parentNode)
{
    var filteredItems = treeViewList.Where(item => 
                                item.ParentID == parentId);

    TreeNode childNode;
    foreach (var i in filteredItems.ToList())
    {
        if (parentNode == null)
            childNode = treeView1.Nodes.Add(i.Text);
        else
            childNode = parentNode.Nodes.Add(i.Text);

        PopulateTreeView(i.ID, childNode);
    }
}

In VB:

Private Sub PopulateTreeView(ByVal parentId As Integer, _
                             ByVal parentNode As TreeNode)
    Dim filteredItems = treeViewList.Where(Function(item) _
                                     item.ParentId = parentId)

    Dim childNode As TreeNode
    For Each i In filteredItems.ToList()
        If parentNode Is Nothing Then
            childNode = TreeView1.Nodes.Add(i.Text)
        Else
            childNode = parentNode.Nodes.Add(i.Text)
        End If
        PopulateTreeView(i.Id, childNode)
    Next
End Sub

The PopulateTreeView method has two parameters: parentId and parentNode. The parentId is the Id value associated with the parent node. The code will find all items in the list with the defined parent Id. The parentNode is the TreeView node under  which the items are added.

The filteredItems variable contains the results of a lambda expression finding all of the items in the list with the passed in parentId.

The code then loops through those items and adds the nodes to the parent node.

It then calls itself, making the method recursive. The method call passes in the node's Id and the node itself. This will cause the method to load all of its child nodes.

When you run the code, the TreeView should appear as follows:

image

Enjoy!

Filed under: , , , ,

Comments

# re: Populating a TreeView Control from a List

Sunday, November 22, 2009 2:03 AM by Sidd

Hello Deborah,

Thank you again for posting such a wonderful blog. Now i have to point out your ability to write simple, precise and very clear explanation in terms of concepts that you explain.

Also almost all the times, the code that you post is tested and workable, and i had no problems with it.

Your blogs are more ever becoming a complete reference for us, where you not only explain the fundamental concepts, but also how to solve the real world problems that we face a lot of times, when we do coding.

Thanks again,

Sidd

# re: Populating a TreeView Control from a List

Tuesday, January 12, 2010 2:40 AM by Axplains

Hello, thanks for your article.

I tried to modify it using data coming from a LinQ query (coming from a database table structured just like your TreeviewItem class) instead of a List, but i could not reproduce the function correctly.

Could you please make an example of this function on data coming from a table?

Thanks a lot in advance.

Ax

# re: Populating a TreeView Control from a List

Tuesday, January 12, 2010 5:16 AM by Axplains

Hello,

further exploring your site I found your very interesting "PurchaseTracker" app, which I am exploring trying to upgrade my understanding of "three layer" architecture and clean code subdivision.

It seems to me that such examples are very rare to find, so thank you very much for sharing.

Anyway, I could not find information about the SQL database underlying the application, nor its definition in order to be able to recreate it myself...

Could you please point a link to its model, or description, or whatever...?

Thanks a lot again

Axplains

# re: Populating a TreeView Control from a List

Wednesday, January 13, 2010 10:19 AM by Deborah Kurata

Hi Axplains -

Thank you for visiting my blog. You should find all of the database scripts in the PTDB subdirectory of the project.

# re: Populating a TreeView Control from a List

Tuesday, March 09, 2010 3:10 PM by Patrick

Your post is very easy to understand and helpful . It rare to find explanatory examples on biz obj like that. Pls more of such

Thanks

# re: Populating a TreeView Control from a List

Saturday, April 10, 2010 12:13 PM by Alessandro

Hi guess I would I modify the above code so that the treeview is populated from a 1d array, instead of a list ?

# re: Populating a TreeView Control from a List

Sunday, April 11, 2010 5:53 PM by Deborah Kurata

Hi Alessandro -

The code should be about the same, as long as the array contains a set of objects that have the Id, ParentId and Text properties.

Hope this helps.

# re: Populating a TreeView with datatable and any columns

Tuesday, May 25, 2010 4:02 PM by Marco Valdez - Lima Peru

Thanks for the example,

this another alternative.

saludos, regards.

////////////////////////////////////////////////////////////////////

       DataTable dt = new DataTable();

       dt.Columns.Add("uno");

       dt.Columns.Add("dos");

       dt.Columns.Add("tres");

       dt.Rows.Add("celda2", "reg1", "dato1");

       dt.Rows.Add("celda2", "reg2", "dato2");

       dt.Rows.Add("celda2", "reg3", "dato3");

       dt.Rows.Add("celda1", "reg1", "dato1");

       dt.Rows.Add("celda1", "reg2", "dato2");

       dt.Rows.Add("celda1", "reg3", "dato3");

       dt.Rows.Add("celda1", "reg3", "dato3");

       TreeView1.Nodes.Add(new TreeNode("**"));

       ordenaColumnas(TreeView1.Nodes[0], dt, new string[] { "uno", "dos" });

   private void ordenaColumnas(TreeNode parentNode, DataTable tabla, string[] columnas)

   {

       DataRow[] registros = tabla.Select("", string.Join(",", columnas) + " asc");

       foreach (DataRow reg in registros)

           cargaNodo(parentNode, reg, columnas, 0);

   }

   private void cargaNodo(TreeNode parentNode, DataRow registro, string[] columnas, int colNum)

   {

       TreeNode childNode, nuevoNodo = new TreeNode(registro[columnas[colNum]].ToString());

       if(!existeNodo(parentNode.ChildNodes, nuevoNodo.Text))

           parentNode.ChildNodes.Add(nuevoNodo);

       if (colNum == columnas.Length - 1) return;

       childNode = parentNode.ChildNodes[getIndexNode(parentNode.ChildNodes, nuevoNodo.Text)];

       cargaNodo(childNode, registro, columnas, colNum + 1);

   }

   private bool existeNodo(TreeNodeCollection nodos, string valor)

   {

       foreach (TreeNode nodo in nodos)

           if (nodo.Text == valor) return true;

       return false;

   }

   private int getIndexNode(TreeNodeCollection nodos, string texto)

   {

       for (int x = 0; x < nodos.Count; x++)

           if (nodos[x].Text == texto) return x;

       return -1;

   }

////////////////////////////////////////////////////////////////////

# re: Populating a TreeView Control from a List

Sunday, August 01, 2010 9:03 PM by Duncan Walsingham

hi Deborah,

It is a very nice article indeed; your algorithm is simple yet ingenious, and can be applied to may programming problems.

In any case, I do have a question though :  assuming we have a strongly-typed list defined, much like your example, treeViewList, with the exception that it has to be constructed in such a way that it simulates the way Microsoft Outlook defines it's Distribution Lists, wherein a DL may have another DL member within it ( in addition to the actual email lists ), in which that DL contains other DL's ).  For example :

Finite Automata Office

----- Brian Kernighan

----- Dennis Ritchie

----- James Gosling

----- E Codd

----- Applications Division

-------------- Bill Gates

-------------- Steve Jobs

-------------- Paul Allen

-------------- Research Division

----------------------- Alan Turing

----------------------- Konrad Zuse

Compiler Office

----- Niklaus Wirth

----- Alain Colmeraur

----- John Kemeny

----- Thomas Kurtz

In the case above, both [Finite Automata Office] and [Compiler Office] have their parent nodes set o null( or Nothing), in which case they become root nodes.  However, embedded within their memberships are other offices/or branches or divisions, in which case the nesting is unlimited and can go on and on.

Guess the question is, if we manually code in their membership list, it would be very easy, as per your example, but how about if the Tree is populated from a pre-defined list in which the parentid's ( or levels ) are not defined yet, but has to be generated by a loop ?

Again, using the sample above, the current DL would be :

1, Finite Automata Office

2, Compiler Office

3, Research Division

4, Applications Division

Then you have another list, say another Data Table wherein it contains the actual membership per defined DL :

1, Finite Automata Office

Members :  

----- Brian Kernighan

----- Dennis Ritchie

----- James Gosling

----- E Codd

2, Compiler Office

Members :

----- Niklaus Wirth

----- Alain Colmeraur

----- John Kemeny

----- Thomas Kurtz

3, Applications Division

Members :

----- Bill Gates

----- Steve Jobs

----- Paul Allen

4, Research Division

Members :

----- Alan Turing

----- Konrad Zuse

So what I am trying to say is, in  a sense, you have to build your treeviewmembership list based on a combination of 2 distinct and separate lists : a main DL List and another membership DL List.  In this case, the nesting of DL's within another DL is infinite, depending on departmental policies.  And since this is policy, then it probably means the lists have already been defined and cannot be altered, we just have to work with what is current.

Any advice is greatly appreciated, thanks so much.

# re: Populating a TreeView Control from a List

Friday, February 25, 2011 2:52 PM by Rodrigo

Very easy and Works like a charm!

Thank you!!

# re: Populating a TreeView Control from a List

Monday, February 20, 2012 12:13 PM by dellmerca

asp.net treeview from vb.net and c#

asp.net-informations.com/.../asp-net-treeview.htm

dell.

Leave a Comment

(required) 
(required) 
(optional)
(required) 
If you can't read this number refresh your screen
Enter the numbers above: