【问题标题】:TreeView, Linq-To-SQL recursive data populationTreeView,Linq-To-SQL 递归数据填充
【发布时间】:2009-02-26 05:39:30
【问题描述】:

我有一个 IEnumerable(of Employee),它与自身有 ParentID/ChildID 关系,我可以将其数据绑定到 TreeView,它可以完美地填充层次结构。但是,我希望能够手动遍历所有记录并以编程方式创建所有节点,以便我可以根据给定项目/无的数据更改每个节点的属性。

有没有解释如何做到这一点的教程?我见过很多使用数据集和数据表的,但没有一个显示如何在 Linq to SQL (IEnumerable) 中做到这一点

更新:

这是我过去使用 DataSet 的方法 - 我似乎无法找到如何使用 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

【问题讨论】:

    标签: linq-to-sql treeview hierarchy


    【解决方案1】:

    如果您只需要一种枚举树的方法,您可以将其实现为生成器,它可能看起来很奇怪,您可能最好使用用户定义的枚举器,但它本质上是一样的。

    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;
        }
    }
    

    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
    

    【讨论】:

    • 什么是“产量”?我认为 VB.NET 没有等价物。
    • 我添加了我以前的代码,因为我无法对您的建议做出正面或反面,以及如何将其应用于我想要完成的事情。我希望这有助于澄清我的问题。
    猜你喜欢
    • 2017-02-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-23
    • 2010-10-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多