7

I have created an account table in my database, with these columns:

ID
Name
ParentID

This is an example of how records have been stored:

ID   Name    ParentID
1    BANK A  0
2    0001    1
3    0002    1
4    BANK B  0
5    0001    4
6    0002    4

But the company name does not come from database, it comes from code. So how can I expand the TreeView like this?

├─ BANK A
│  ├─ 0001
│  └─ 0002
└─ BANK B
   ├─ 0001
   └─ 0002

How can I do this in C#? I also tried from HERE but I still don't understand it.

Reza Aghaei
  • 120,393
  • 18
  • 203
  • 398
Azri Zakaria
  • 1,324
  • 5
  • 23
  • 52

2 Answers2

7

i have found a piece of code that worked great for me after spending 2h to make complicated algorithlms :

 //In Page load
 //select where id is null to retrieve the parent nodes 
 //in a datatable (called table here)
 foreach (DataRow row in table.Rows)
 {
   TreeNode node = new TreeNode();
   node.Text = row["title"].ToString();
   node.Value = row["id"].ToString();
   //you can affect the node.NavigateUrl

   node.PopulateOnDemand = true;
   TreeView1.Nodes.Add(node);
 }

then create the TreeNodePopulate event :

 protected void TreeView1_TreeNodePopulate(Object sender, TreeNodeEventArgs e)
 {
     string id= e.Node.Value;
     //do your "select from yourTable where parentId =" + id;

     foreach (DataRow row in table.Rows)
     {
         TreeNode node = new TreeNode(row["title"], row["id"])
         node.PopulateOnDemand = true;    
         e.Node.ChildNodes.Add(node);
     }

 }

it worked like hell for me, i hope it will help !

Sebastien H.
  • 6,818
  • 2
  • 28
  • 36
  • Code is either missing, or in error: A WinForm TreeView TreeNode has no 'PopulateOnDemand property. – BillW Jun 10 '19 at 17:27
  • This code is nearly 6 years old, you may need to find a equivalent method. I haven't touched C# since. – Sebastien H. Jun 13 '19 at 18:06
  • 'PopulateOnDemand is in System.Web.UI.WebControls this is a WinForm question. – BillW Jun 14 '19 at 20:11
  • The event "TreeNodePopulate" is too good to be true in the case of WinForms. Most form designers will pick up on that right away. For those reading.. @BillW explained. – WLFree Oct 15 '22 at 21:28
3

To populate a TreeView from a DataTable or any IEnumerable<T>, you should be able to answer the following questions:

  1. What are data source items
  2. How to detect if an item in data source is a root item in tree
  3. How to find child items of an item in data source
  4. How to create tree item from data source item.

By passing answer of above questions as lambda expressions to the following method, it uses a recursive algorithm to create a list of TreeNode which you can add to TreeView. Each TreeNode contains the descendant TreeNode items:

private IEnumerable<TreeNode> GetTreeNodes<T>(
    IEnumerable<T> source,
    Func<T, Boolean> isRoot,
    Func<T, IEnumerable<T>, IEnumerable<T>> getChilds,
    Func<T, TreeNode> getItem)
{
    IEnumerable<T> roots = source.Where(x => isRoot(x));
    foreach (T root in roots)
        yield return ConvertEntityToTreeNode(root, source, getChilds, getItem); ;
}

private TreeNode ConvertEntityToTreeNode<T>(
    T entity,
    IEnumerable<T> source,
    Func<T, IEnumerable<T>, IEnumerable<T>> getChilds,
    Func<T, TreeNode> getItem)
{
    TreeNode node = getItem(entity);
    var childs = getChilds(entity, source);
    foreach (T child in childs)
        node.Nodes.Add(ConvertEntityToTreeNode(child, source, getChilds, getItem));
    return node;
}

Example

I assume you have loaded data into the following structure:

var dt = new DataTable();
dt.Columns.Add("Id", typeof(int));
dt.Columns.Add("Name", typeof(string));
dt.Columns.Add("ParentId", typeof(int));

dt.Rows.Add(1, "Menu 1", DBNull.Value);
dt.Rows.Add(11, "Menu 1-1", 1);
dt.Rows.Add(111, "Menu 1-1-1", 11);
dt.Rows.Add(112, "Menu 1-1-2", 11);
dt.Rows.Add(12, "Menu 1-2", 1);
dt.Rows.Add(121, "Menu 1-2-1", 12);
dt.Rows.Add(122, "Menu 1-2-2", 12);
dt.Rows.Add(123, "Menu 1-2-3", 12);
dt.Rows.Add(124, "Menu 1-2-4", 12);
dt.Rows.Add(2, "Menu 2", DBNull.Value);
dt.Rows.Add(21, "Menu 2-1", 2);
dt.Rows.Add(211, "Menu 2-1-1", 21);

Then to convert it nodes of a TreeView, you can use the following code:

var source = dt.AsEnumerable();
var nodes = GetTreeNodes(
        source,
        (r) => r.Field<int?>("ParentId") == null,
        (r, s) => s.Where(x => r["Id"].Equals(x["ParentId"])),
        (r) => new TreeNode { Text = r.Field<string>("Name") }
);
treeView1.Nodes.AddRange(nodes.ToArray());

As a result, you will have the following tree structure:

├─ Menu 1
│  ├─ Menu 1-1
│  │  ├─ Menu 1-1-1
│  │  └─ Menu 1-1-2
│  └─ Menu 1-2
│     ├─ Menu 1-2-1
│     ├─ Menu 1-2-2
│     ├─ Menu 1-2-3
│     └─ Menu 1-2-4
└─ Menu 2
   └─ Menu 2-1
      └─ Menu 2-1-1
Reza Aghaei
  • 120,393
  • 18
  • 203
  • 398