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);
}
-
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\$radarbob– radarbob2022年03月14日 07:58:12 +00:00Commented Mar 14, 2022 at 7:58
1 Answer 1
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 ValueTuple
s 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);
}
-
1\$\begingroup\$ It seems from the question text that the asker is interested in the
PopTree
algorithm and thePopulate
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\$phoog– phoog2022年03月17日 08:11:20 +00:00Commented Mar 17, 2022 at 8:11 -
1\$\begingroup\$ @phoog Yes that's right the question is more about the
PopTree
. But thatPopulate
code was shouting for improvement :) \$\endgroup\$Peter Csala– Peter Csala2022年03月17日 08:13:50 +00:00Commented Mar 17, 2022 at 8:13 -
\$\begingroup\$ That is certainly true. \$\endgroup\$phoog– phoog2022年03月17日 08:15:50 +00:00Commented Mar 17, 2022 at 8:15