如何将数据表转换为树视图
How to convert a datatable to a treeview
我有一个数据table类似于下面的数据:
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
我想从这个 table:
中获得类似于下面的树视图
jack
|_ 12
|_ US
|_ Jap
joe
|_ 5
| |_ It
|_ 16
|_ Ven
will
|_ 15
| |_ SA
|_ 9
|_ Fr
table 的列数和行数可能更多或更少。
为了构建树视图,我有一个自定义节点 class,如下所示:
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;
}
}
这就是我向树中添加节点的方式:
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);
为此我得到了下面的树:
root
Node A
Node B
Node C
Node D
Node E
如何在 C# 中执行此操作?
如有任何意见,我们将不胜感激。
假设:
- 每列数据代表新的(或现有的)节点
for example:
if jack
in row[0]
=> col1
and col4
refers to the same node
12
in row[1]
=> col1
and col4
refers to the same node (of Jack
)
and so on...
- 数据表中的每一行代表另一个级别的节点...
然后您需要遍历列和行以将数据转换为 Node
的列表。
注意:在下面的示例中,我使用 List<Node>
而不是 ObservableCollection<Node>()
,但这应该会给您一个想法...
这是一个Node
class定义:
class Node
{
public string Name{get; set;}
public List<Node> Children {get; set;}
}
注意:由于循环引用,我删除了 Parent
成员。
用法(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();
在现实世界中,我建议创建助手 class...
我有一个数据table类似于下面的数据:
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
我想从这个 table:
中获得类似于下面的树视图jack
|_ 12
|_ US
|_ Jap
joe
|_ 5
| |_ It
|_ 16
|_ Ven
will
|_ 15
| |_ SA
|_ 9
|_ Fr
table 的列数和行数可能更多或更少。
为了构建树视图,我有一个自定义节点 class,如下所示:
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;
}
}
这就是我向树中添加节点的方式:
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);
为此我得到了下面的树:
root
Node A
Node B
Node C
Node D
Node E
如何在 C# 中执行此操作?
如有任何意见,我们将不胜感激。
假设:
- 每列数据代表新的(或现有的)节点
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...
- 数据表中的每一行代表另一个级别的节点...
然后您需要遍历列和行以将数据转换为 Node
的列表。
注意:在下面的示例中,我使用 List<Node>
而不是 ObservableCollection<Node>()
,但这应该会给您一个想法...
这是一个Node
class定义:
class Node
{
public string Name{get; set;}
public List<Node> Children {get; set;}
}
注意:由于循环引用,我删除了 Parent
成员。
用法(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();
在现实世界中,我建议创建助手 class...