0
\$\begingroup\$

I have a DataTable with id, parent, label columns and want to populate a TreeView with it.

I'm new to c# and as far as I understand, there is no ready solution for it, unlike some other languages.

So I sorted the data hierarchically at DataTable level and wrote not a very pretty recursive method.

Is this a good solution or can it be greatly improved?

 using System.Data;
 public void Populate()
 {
 //data example
 var table = new DataTable();
 DataColumn column;
 DataRow row;
 column = new DataColumn(); column.DataType = Type.GetType("System.Int32"); column.ColumnName = "id"; table.Columns.Add(column);
 column = new DataColumn(); column.DataType = Type.GetType("System.Int32"); column.ColumnName = "parent"; table.Columns.Add(column);
 column = new DataColumn(); column.DataType = Type.GetType("System.String"); column.ColumnName = "label"; table.Columns.Add(column);
 row = table.NewRow(); row["id"] = 1; row["parent"] = DBNull.Value; row["label"] = "root1"; table.Rows.Add(row);
 row = table.NewRow(); row["id"] = 2; row["parent"] = 1; row["label"] = "child11"; table.Rows.Add(row);
 row = table.NewRow(); row["id"] = 3; row["parent"] = 1; row["label"] = "child12"; table.Rows.Add(row);
 row = table.NewRow(); row["id"] = 4; row["parent"] = DBNull.Value; row["label"] = "root2"; table.Rows.Add(row);
 row = table.NewRow(); row["id"] = 5; row["parent"] = 4; row["label"] = "child21"; table.Rows.Add(row);
 row = table.NewRow(); row["id"] = 6; row["parent"] = 5; row["label"] = "child211"; table.Rows.Add(row);
 // call method
 int i = 0;
 var result = new List<TreeNode>();
 var data = table.Rows;
 PopTree(ref data, DBNull.Value, ref i, ref result);
 treeView1.Nodes.AddRange(result.ToArray());
 }
 private void PopTree(ref DataRowCollection data, object parent, ref int i, ref List<TreeNode> result)
 {
 if (i >= data.Count || data[i]["parent"].ToString() != parent.ToString())
 {
 return;
 }
 var row = data[i];
 var children = new List<TreeNode>();
 i++;
 if (i < data.Count && row["id"].ToString() == data[i]["parent"].ToString())
 {
 PopTree(ref data, row["id"], ref i, ref children);
 }
 TreeNode node = new TreeNode(row["label"].ToString(), children.ToArray());
 result.Add(node);
 PopTree(ref data, parent, ref i, ref result);
 }
asked Mar 13, 2022 at 22:01
\$\endgroup\$
1
  • 2
    \$\begingroup\$ ... or can it be greatly improved? That is a much more open question than you may realize. Perhaps read this SO thread for starters: Tree Data Structure in C# \$\endgroup\$ Commented Mar 14, 2022 at 7:58

1 Answer 1

1
\$\begingroup\$

Let me focus only on the Populate function in this post.

Defining Columns

You can define columns in a really concise way thanks to the AddRange method of the DataColumnCollection class

table.Columns.AddRange(new[] {
 new DataColumn("id", typeof(int)),
 new DataColumn("parent", typeof(int)), 
 new DataColumn("label", typeof(string)),
});

I would also advice to use typeof operator over Type.GetType

  • since the former can give you compile time safety
  • whereas the latter can fail at runtime in case of a typo for example.

Populating Rows with data

Unfortunately DataRowCollection does not define an AddRange method so, you have to add the rows one-by one. Here the preferred approach is to define the data separately from the DataRow population.

Here I have created an array of ValueTuples to represent only the data.

var relationships = new (int Id, int? Parent, string Label)[] {
 (1, null, "root1"),
 (2, 1, "child11"),
 (3, 1, "child12"),
 (4, null, "root2"),
 (5, 4, "child21"),
 (6, 5, "child211"),
};

Finally here is a foreach to convert the data into a DataRow then add it to the DataTable

foreach (var relationship in relationships)
{
 var row = table.NewRow();
 row[0] = relationship.Id;
 if (relationship.Parent.HasValue)
 row[1] = relationship.Parent;
 else
 row[1] = DBNull.Value;
 row[2] = relationship.Label;
 table.Rows.Add(row);
}
answered Mar 16, 2022 at 12:30
\$\endgroup\$
3
  • 1
    \$\begingroup\$ It seems from the question text that the asker is interested in the PopTree algorithm and the Populate method is provided for the sake of having a working example. The advice in this answer is sound, but it seems not to answer the question. \$\endgroup\$ Commented Mar 17, 2022 at 8:11
  • 1
    \$\begingroup\$ @phoog Yes that's right the question is more about the PopTree. But that Populate code was shouting for improvement :) \$\endgroup\$ Commented Mar 17, 2022 at 8:13
  • \$\begingroup\$ That is certainly true. \$\endgroup\$ Commented Mar 17, 2022 at 8:15

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.