Click here to Skip to main content
15,064,665 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
I have a data table as following

ID    Name   ParentID
1      A       0
2      B       1
3      C       1
4      D       2
5      E       3
6      F       4

I want this as a List<chart>

 public int ID { get; set; }
 public string Name { get; set; }
 public string ParentID{ get; set; }
 public List<chart> lstChild{ get; set; }

What I have tried:

I have tried this function:

public static void MakeTree(DataTable dt, clsChart parent)
            foreach (DataRow row in dt.AsEnumerable().Where(x => x.Field<int>("ParentID") == parent.ID))
                if (parent.lstChildren == null)
                    parent.lstChildren = new List<clschart>();
                clsChart newNode = new clsChart();
                newNode.Name = row.Field<string>("Name");
                newNode.ID = row.Field<int>("EntryID");
                MakeTree(dt, newNode);

But it doesn't return List<>, it returns the class
Updated 28-Mar-19 19:36pm

As to me, your datatable is designed properly for hierarchical data model[^]. That's why a chart model should reflect to a datatable model.
public class chart
	public int ID { get; set; }
 	public string Name { get; set; }
	public int ParentID{ get; set; }

This is very easy to create a List<chart> from your datatable:
List<chart> charts = dt.AsEnumerable()
    .Select(dr=> new chart()

Above model is a "flat" version of hierarchical data. In case you want to create more advanced hierarchical structure, please, read this: Recursive Hierarchical Joins in C# and LINQ - Bitlush[^]
You can recursively create (and link) your nodes, but you also need a "master list" that you add to when you create each node.

The "master list" represents the fully expanded tree; a node is expandable / collapsible if it has children.

"Canned" tree views maintain an internal "tree view list" (same thing).

The "level" of each item determines the indenting.

Adding a "level number" is useful when creating tree. With a level number, you can also infer the parent, if any, when using compound keys.
Firstly, ParentID should be an int, not a string

Secondly, you don't need recursion at all, and provided your parent nodes are always defined before their children, you can use a single loop. (If it's a random order, then create a node collection first, and then loop through that afterwards:
class Chart
    private static Dictionary<int, Chart> all = new Dictionary<int, Chart>();
    public int ID { get; set; }
    public string Name { get; set; }
    public int ParentID { get; set; }
    public List<Chart> Children { get; set; } = new List<Chart>();
    private Chart(DataRow row)
        ID = (int)row["ID"];
        Name = (string)row["Name"];
        ParentID = (int)row["ParentID"];
        all[ID] = this;
    public static Chart MakeTree(DataTable dt)
        List<Chart> nodes = new List<Chart>();
        Chart root = null;
        foreach (DataRow row in dt.AsEnumerable())
            Chart node = new Chart(row);
            if (node.ParentID == 0)
                if (root != null) throw new ArgumentException("Too many ROOT nodes: only one was expected.");
                root = node;
                if (root == null) throw new ArgumentException("ROOT node has not been defined: one is required.");
                Chart parent = all[node.ParentID];
        return root;

DataTable 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, "A", 0);
dt.Rows.Add(2, "B", 1);
dt.Rows.Add(3, "C", 1);
dt.Rows.Add(4, "D", 2);
dt.Rows.Add(5, "E", 3);
dt.Rows.Add(6, "F", 4);
Chart root = Chart.MakeTree(dt);
prapti.n3 27-Mar-19 4:23am
But I want it in List<chart> type not as Chart object
OriginalGriff 27-Mar-19 4:36am
You have one root node: this contains a List of all the child Chart items. The only List of all items you could create would contain one item: the root node. All the others are child nodes of that root.

So why would you want that at all?
prapti.n3 27-Mar-19 4:40am
Because this is only an example. The data on which i am working has 3-4 root with parent ID 0.
OriginalGriff 27-Mar-19 4:56am
So create a "dummy node" with ID 0, and then return the child list from that!

Or, add a collection of nodes to return, and add all nodes with a parent of 0 to that instead of limiting it to one root.
List<clschart> lstChart = new List<clschart>();
string JSONresult;

//var roots = dt.AsEnumerable().ToList();
lstChart = clsDataTables.ConvertDataTable<clschart>(dt);
var roots = lstChart.Where(f => f.ParentID == 0).ToList();
//(from n in dt.AsEnumerable() where n.Field<int>("ParentID") == 0 group n by n.Field<int>("ParentID")).ToList();
foreach (var root in roots)
clsChart.BuildTree(root, lstChart);

JSONresult = JsonConvert.SerializeObject(roots, Formatting.Indented);

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

CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900