To see the C# version of my answer see this post.
To populate a TreeView
from a DataTable
or any IEnumerable(Of T)
, you should be able to answer the following questions:
- What are data source items
- How to detect if an item in data source is a root item in tree
- How to find child items of an item in data source
- How to create tree item from data source item.
By passing answer of above questions as lambda expressions to the following method, it uses a recursive algorithm to create a list of TreeNode
which you can add to TreeView
. Each TreeNode
contains the descendant TreeNode
items:
Private Iterator Function GetTreeNodes(Of T)(
ByVal source As IEnumerable(Of T),
ByVal isRoot As Func(Of T, Boolean),
ByVal getChilds As Func(Of T, IEnumerable(Of T), IEnumerable(Of T)),
ByVal getItem As Func(Of T, TreeNode)) As IEnumerable(Of TreeNode)
Dim roots As IEnumerable(Of T) = source.Where(Function(x) isRoot(x))
For Each root As T In roots
Yield ConvertEntityToTreeNode(root, source, getChilds, getItem)
Next
End Function
Private Function ConvertEntityToTreeNode(Of T)(
ByVal entity As T,
ByVal source As IEnumerable(Of T),
ByVal getChilds As Func(Of T, IEnumerable(Of T), IEnumerable(Of T)),
ByVal getItem As Func(Of T, TreeNode)) As TreeNode
Dim node As TreeNode = getItem(entity)
Dim childs = getChilds(entity, source)
For Each child As T In childs
node.Nodes.Add(ConvertEntityToTreeNode(child, source, getChilds, getItem))
Next
Return node
End Function
Example
I assume you have loaded data into the following structure:
Dim dt = New DataTable()
dt.Columns.Add("Id", GetType(Integer))
dt.Columns.Add("Name", GetType(String))
dt.Columns.Add("ParentId", GetType(Integer))
dt.Rows.Add(1, "Menu 1", DBNull.Value)
dt.Rows.Add(11, "Menu 1-1", 1)
dt.Rows.Add(111, "Menu 1-1-1", 11)
dt.Rows.Add(112, "Menu 1-1-2", 11)
dt.Rows.Add(12, "Menu 1-2", 1)
dt.Rows.Add(121, "Menu 1-2-1", 12)
dt.Rows.Add(122, "Menu 1-2-2", 12)
dt.Rows.Add(123, "Menu 1-2-3", 12)
dt.Rows.Add(124, "Menu 1-2-4", 12)
dt.Rows.Add(2, "Menu 2", DBNull.Value)
dt.Rows.Add(21, "Menu 2-1", 2)
dt.Rows.Add(211, "Menu 2-1-1", 21)
Then to convert it nodes of a TreeView
, you can use the following code:
Dim source = dt.AsEnumerable()
Dim nodes = GetTreeNodes(
source,
Function(r) r.Field(Of Integer?)("ParentId") Is Nothing,
Function(r, s) s.Where(Function(x) r("Id").Equals(x("ParentId")) ),
Function(r) New TreeNode With {.Text = r.Field(Of String)("Name")})
TreeView1.Nodes.AddRange(nodes.ToArray())
As a result, you will have the following tree structure:
├─ Menu 1
│ ├─ Menu 1-1
│ │ ├─ Menu 1-1-1
│ │ └─ Menu 1-1-2
│ └─ Menu 1-2
│ ├─ Menu 1-2-1
│ ├─ Menu 1-2-2
│ ├─ Menu 1-2-3
│ └─ Menu 1-2-4
└─ Menu 2
└─ Menu 2-1
└─ Menu 2-1-1