I have a datatable similar to the one below:
col1 col2 col3 col4 col5 col6
name jack joe will jack joe will
age 12 5 15 12 16 9
origin US It SA Jap Ven Fr
I want to get a treeview similar to the one below from this table:
jack
|_ 12
|_ US
|_ Jap
joe
|_ 5
| |_ It
|_ 16
|_ Ven
will
|_ 15
| |_ SA
|_ 9
|_ Fr
The table may have more or less number of columns and rows.
To build the treeview I have a custom Node class as below:
public class Node : PropertyChangedBase
{
private ObservableCollection<Node> mChildren;
// Add all of the properties of a node here. In this example,
// all we have is a name and whether we are expanded.
public string Name
{
get { return _name; }
set
{
if (_name != value)
{
_name = value;
NotifyOfPropertyChange(() => Name);
}
}
}
private string _name;
public bool IsExpanded
{
get { return _isExpanded; }
set
{
if (_isExpanded != value)
{
_isExpanded = value;
NotifyOfPropertyChange(() => IsExpanded);
}
}
}
private bool _isExpanded;
// Children are required to use this in a TreeView
public IList<Node> Children { get { return mChildren; } }
// Parent is optional. Include if you need to climb the tree
// from code. Not usually necessary.
public Node Parent { get; private set; }
public Node(Node parent = null)
{
mChildren = new ObservableCollection<Node>();
IsExpanded = true;
Parent = parent;
}
}
and this is how I add nodes to the tree:
mRootNodes = new ObservableCollection<Node>();
// Test data for example purposes
Node root = new Node() { Name = "Root" };
Node a = new Node(root) { Name = "Node A" };
root.Children.Add(a);
Node b = new Node(root) { Name = "Node B" };
root.Children.Add(b);
Node c = new Node(b) { Name = "Node C" };
b.Children.Add(c);
Node d = new Node(b) { Name = "Node D" };
b.Children.Add(d);
Node e = new Node(root) { Name = "Node E" };
root.Children.Add(e);
mRootNodes.Add(root);
For which I get the below tree:
root
Node A
Node B
Node C
Node D
Node E
How can I do this in C#?
Any comment is appreciated.
Assuming that:
for example:
if
jack
inrow[0]
=>col1
andcol4
refers to the same node
12
inrow[1]
=>col1
andcol4
refers to the same node (ofJack
)and so on...
then you need to loop through the columns and rows to convert data into list of Node
's.
Note: In the below example i'm using List<Node>
instead of ObservableCollection<Node>()
, but this should give you an idea...
This is a Node
class definition:
class Node
{
public string Name{get; set;}
public List<Node> Children {get; set;}
}
Note: i removed Parent
member due to circular reference.
Usage (LinqPad):
DataTable dt = new DataTable();
dt.Columns.Add(new DataColumn("prop", typeof(string)));
dt.Columns.AddRange(Enumerable.Range(1,6).Select(x=>new DataColumn($"col{x}", typeof(string))).ToArray());
dt.Rows.Add(new object[]{"name", "jack", "joe", "will", "jack", "joe", "will"});
dt.Rows.Add(new object[]{"age", "12", "5", "15", "12", "16", "9"});
dt.Rows.Add(new object[]{"origin", "US", "It", "SA", "Jap", "Ven", "Fr"});
List<Node> nodes = new List<Node>();
for(int c=1; c<dt.Columns.Count; c++)
{
Node parent = null;
Node current = null;
for(int r=0; r<dt.Rows.Count; r++)
{
DataRow dr = dt.Rows[r];
string name = Convert.ToString(dr[c]);
if(parent==null)
{
parent = new Node(){Name = name, Children= new List<Node>()};
current = nodes.Where(x=>x.Name==parent.Name).SingleOrDefault();
if(current==null)
nodes.Add(parent);
else
parent = current;
}
else
{
current = new Node(){Name = name, Children= new List<Node>()};
if(parent.Children.Where(x=>x.Name==current.Name).SingleOrDefault()==null)
parent.Children.Add(current);
else
current = parent.Children.Where(x=>x.Name==current.Name).SingleOrDefault();
parent = current;
}
}
}
nodes.Dump();
In a real world, i'd suggest to create helper class...