문제

TreeView에 데이터 바인딩할 수 있고 계층 구조를 완벽하게 채울 수 있는 ParentID/ChildID 관계가 있는 IEnumerable(직원)이 있습니다.그러나 모든 레코드를 수동으로 반복하고 모든 노드를 프로그래밍 방식으로 생성하여 해당 항목에 대한 데이터를 기반으로 각 노드의 속성을 변경할 수 있기를 원합니다.

이 작업을 수행하는 방법을 설명하는 튜토리얼이 있나요?데이터 세트와 데이터 테이블을 사용하는 많은 것을 보았지만 Linq에서 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
도움이 되었습니까?

해결책

트리를 열거하는 방법이 필요한 경우 이를 생성기로 구현할 수 있습니다. 이상해 보일 수 있으며 사용자 정의 열거자를 사용하는 것이 더 나을 수도 있지만 본질적으로 동일합니다.

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에는 항복 키워드가 존재하지 않는 것 같습니다.하지만 여전히 이를 수행하는 클래스를 작성할 수 있습니다.

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
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top