linq-to-sql - TreeView,Linq-To-SQL 递归数据填充

标签 linq-to-sql treeview hierarchy

我有一个 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/

相关文章:

c# - 如何使用存储过程在 LINQ to SQL 中使用事务?

c# - Group join 导致 IQueryable 变成 IEnumerable,为什么?

c# - LINQ to SQL 关联映射

c# - 从单个字符串列请求 1..N 值时,QueryAsync() 返回什么?

c++ - 如何从节点的父节点列表构建树?

c# - ItemContainerStyle 中的 Caliburn Micro Action - 未找到方法的目标

treeview - UI5树表为什么重复节点?

wpf - 在显示时修改 ObservableCollection

ios - 在 UIKit View 层次结构中感到困惑

mongodb - 递归查询?