TreeView、Linq-To-SQL 递归数据填充
我有一个 IEnumerable(of Employee),其自身具有 ParentID/ChildID 关系,我可以将其数据绑定到 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
I have an IEnumerable(of Employee) with a ParentID/ChildID relationship with itself that I can databind to a TreeView and it populates the hierarchy perfectly. However, I want to be able to manually loop through all the records and create all the nodes programmatically so that I can change the attributes for each node based on the data for that given item/none.
Is there a tutorial out there that explains how to do this? I've seen many that use datasets and datatables but none that show how to do it in Linq to SQL (IEnumerable)
UPDATE:
Here's how I used to do it with a DataSet - I just can't seem to find how to do the same with 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
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
如果您只需要一种枚举树的方法,您可以将其实现为生成器,它可能看起来很奇怪,您可能更适合使用用户定义的枚举器,但它本质上是相同的事情。
TEntity : IGetChildItems 的类型约束只是表示您需要抽象如何降低层次结构。 如果没有上面的代码就无法编译。
这将以广度优先的方式枚举树,它将首先产生父元素,然后是它的子元素,然后是这些子元素的子元素。 您可以轻松地自定义上述代码以实现不同的行为。
编辑:
yield 返回的东西告诉编译器它应该返回一个值然后继续。 Yield 是一个上下文关键字,仅允许在迭代语句中使用。 生成器是编写 IEnumerable 数据源的简单方法。 编译器将根据此代码构建一个状态机并创建一个可枚举的匿名类。 显然VB.NET中不存在yield关键字。 但您仍然可以编写一个类来执行此操作。
If you just need a way of enumerating the tree you can implement this as a generator, it might look strange, you're probably better of with a user defined enumerator but it's essentially the same thing.
The type constraint where TEntity : IGetChildItems is just to signify that you need to abstract how to descend the hierarchy. Without the above code would not compile.
This will enumerate the tree in a breadth first fashion, it will yield the parent element first then it's children, and then the children of those children. You can easily customize the above code to achieve a different behavior.
Edit:
The yield return stuff tells the compiler that it should return a value then continue. yield is a context keyword and it's only allowed inside an iterative statement. A generator is a simple way of writing a IEnumerable data source. The compiler will build a state machine from this code and create an enumerable anonymous class. Apparently the yield keyword does not exist in VB.NET. But you can still write a class which does this.