Frage

Ich habe ein IEnumerable (Employee) mit einer ParentID / ChildID Beziehung mit mir selbst, dass ich zu einem TreeView Databind kann und es füllt die Hierarchie perfekt. Allerdings mag ich programmatisch manuell eine Schleife durch alle Aufzeichnungen und erstellen Sie alle Knoten in der Lage sein, so dass ich die Attribute für jeden Knoten auf den Daten für das jeweilige Element / keine Basis ändern kann.

Gibt es ein Tutorial gibt, die erklärt, wie dies zu tun? Ich habe viele gesehen, dass die Verwendung Datensätze und Datentabellen, aber keine, die zeigen, wie es in Linq to SQL (IEnumerable) tun

UPDATE:

Hier ist, wie habe ich es mit einem Datensatz zu tun -. Ich kann einfach nicht scheinen zu finden, wie man das gleiche mit IEnumerable zu tun

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
War es hilfreich?

Lösung

Wenn Sie nur einen Weg Aufzählen den Baum müssen Sie dies als Generator implementieren kann, ist es seltsam aussehen könnte, sind Sie wahrscheinlich besser mit einem benutzerdefinierten Aufzählungs aber es ist im Wesentlichen dasselbe.

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

Der Typ Einschränkung wo TEntity: IGetChildItems gerade ist, um anzuzeigen, dass Sie zu abstrahieren müssen, wie die Hierarchie hinunter. Ohne den oben genannten Code nicht kompiliert werden.

Damit wird der Baum in einer Breiten Mode aufzuzählen, wird es das übergeordnete Element ergeben zuerst, dann ist es die Kinder, und dann werden die Kinder dieser Kinder. Sie können den obigen Code leicht anpassen, ein anderes Verhalten zu erreichen.

Edit:

Die Ausbeute Return Material weist den Compiler an, dass es einen Wert zurückgeben sollte dann weiter. Ausbeute ist ein Kontext Schlüsselwort und es ist nur innerhalb einer iterativen Anweisung erlaubt. Ein Generator ist eine einfache Art und Weise eine IEnumerable Datenquelle zu schreiben. Der Compiler wird eine Zustandsmaschine von diesem Code erstellen und eine zählbare anonyme Klasse erstellen. Offenbar ist die Ausbeute Schlüsselwort existiert nicht in VB.NET. Aber man kann immer noch eine Klasse schreiben, die dies tut.

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
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top