我有一个 IEnumerable(of Employee),它与自身具有 ParentID/ChildID 关系,我可以将其数据绑定(bind)到 TreeView,它完美地填充了层次结构。但是,我希望能够手动遍历所有记录并以编程方式创建所有节点,以便我可以根据给定项目/无的数据更改每个节点的属性。
是否有说明如何执行此操作的教程?我见过很多使用数据集和数据表的,但没有一个显示如何在 Linq to SQL (IEnumerable) 中执行此操作
更新:
这是我过去使用数据集执行此操作的方法 - 我似乎无法找到如何使用 IEnumerable 执行相同操作。
Private Sub GenerateTreeView()
Dim ds As New DataSet()
Dim tasktree As New Task(_taskID)
Dim dt As DataTable = tasktree.GetTaskTree()
ds.Tables.Add(dt)
ds.Relations.Add("NodeRelation", dt.Columns("TaskID"), dt.Columns("ParentID"))
Dim dbRow As DataRow
For Each dbRow In dt.Rows
If dbRow("TaskID") = _taskID Then
Dim node As RadTreeNode = CreateNode(dbRow("Subject").ToString(), False, dbRow("TaskID").ToString())
RadTree1.Nodes.Add(node)
RecursivelyPopulate(dbRow, node)
End If
Next dbRow
End Sub
Private Sub RecursivelyPopulate(ByVal dbRow As DataRow, ByVal node As RadTreeNode)
Dim childRow As DataRow
Dim StrikeThrough As String = ""
Dim ExpandNode As Boolean = True
For Each childRow In dbRow.GetChildRows("NodeRelation")
Select Case childRow("StatusTypeID")
Case 2
StrikeThrough = "ActiveTask"
Case 3
StrikeThrough = "CompletedTask"
ExpandNode = False
Case 4, 5
StrikeThrough = "ClosedTask"
ExpandNode = False
Case Else
StrikeThrough = "InactiveTask"
ExpandNode = False
End Select
Dim childNode As RadTreeNode = CreateNode("<span class=""" & StrikeThrough & """><a href=""Task.aspx?taskid=" & childRow("TaskID").ToString() & """>" & childRow("Subject").ToString() & "</a></span>", ExpandNode, childRow("TaskID").ToString())
node.Nodes.Add(childNode)
RecursivelyPopulate(childRow, childNode)
ExpandNode = True
Next childRow
End Sub
Private Function CreateNode(ByVal [text] As String, ByVal expanded As Boolean, ByVal id As String) As RadTreeNode
Dim node As New RadTreeNode([text])
node.Expanded = expanded
Return node
End Function
最佳答案
如果您只需要一种枚举树的方法,您可以将其实现为生成器,它可能看起来很奇怪,您可能最好使用用户定义的枚举器,但它本质上是一样的。
public interface IGetChildItems<TEntity>
{
IEnumerable<TEntity> GetChildItems();
}
public static IEnumerable<TEntity> Flatten<TEntity>(TEntity root)
where TEntity : IGetChildItems<TEntity>
{
var stack = new Stack<TEntity>();
stack.Push(root);
while (stack.Count > 0)
{
var item = stack.Pop();
foreach (var child in item.GetChildItems())
{
stack.Push(child);
}
yield return item;
}
}
类型约束 where TEntity : IGetChildItems 只是表示您需要抽象如何降低层次结构。没有上述代码将无法编译。
这将以广度优先的方式枚举树,它将首先产生父元素,然后是子元素,然后是这些子元素的子元素。您可以轻松自定义上述代码以实现不同的行为。
编辑:
yield return 告诉编译器它应该返回一个值然后继续。 yield 是一个上下文关键字,它只允许在迭代语句中使用。生成器是一种编写 IEnumerable 数据源的简单方法。编译器将从该代码构建一个状态机并创建一个可枚举的匿名类。显然 VB.NET 中不存在 yield 关键字。但是您仍然可以编写一个类来执行此操作。
Imports System
Imports System.Collections
Imports System.Collections.Generic
Public Class HierarchyEnumerator(Of TEntity As IGetChildItems(Of TEntity))
Implements IEnumerator(Of TEntity), IDisposable, IEnumerator
Public Sub New(ByVal root As TEntity)
Me.stack = New Stack(Of TEntity)
Me.stack.Push(root)
End Sub
Public Sub Dispose()
End Sub
Public Function MoveNext() As Boolean
Do While (Me.stack.Count > 0)
Dim item As TEntity = Me.stack.Pop
Dim child As TEntity
For Each child In item.GetChildItems
Me.stack.Push(child)
Next
Me.current = item
Return True
Loop
Return False
End Function
Public Sub Reset()
Throw New NotSupportedException
End Sub
Public ReadOnly Property Current() As TEntity
Get
Return Me.current
End Get
End Property
Private ReadOnly Property System.Collections.IEnumerator.Current As Object
Get
Return Me.Current
End Get
End Property
Private current As TEntity
Private stack As Stack(Of TEntity)
End Class
关于linq-to-sql - TreeView,Linq-To-SQL 递归数据填充,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/589243/