Domanda

Ho un IEnumerable (di dipendenti) con un / rapporto ChildID ParentID con se stessa che posso DataBind ad un TreeView e popola la gerarchia perfettamente. Tuttavia, voglio essere in grado di ciclo manualmente attraverso tutti i record e creare tutti i nodi a livello di codice in modo che possa modificare gli attributi per ciascun nodo sulla base dei dati relativi a quel dato elemento / nessuno.

C'è un tutorial là fuori che spiega come fare questo? Ho visto tanti che uso serie di dati e DataTable ma nessuno che mostrano come farlo in LINQ to SQL (IEnumerable)

UPDATE:

Ecco come ho usato per farlo con un DataSet -. Io proprio non riesco a trovare il modo di fare lo stesso con 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
È stato utile?

Soluzione

Se avete solo bisogno di un modo di enumerare l'albero è possibile implementare questo come un generatore, potrebbe sembrare strano, probabilmente stai meglio di un enumeratore definito dall'utente ma è essenzialmente la stessa cosa.

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

Il tipo di vincolo in cui TEntity: IGetChildItems è solo per indicare che è necessario astratta come scendere la gerarchia. Senza il codice di cui sopra non sarebbe la compilazione.

Questo enumerare l'albero in un largo prima di moda, si produrrà l'elemento padre prima allora è bambini, e poi i figli di quei bambini. Si può facilmente personalizzare il codice qui sopra per ottenere un comportamento diverso.

Modifica:

La roba dei rendimenti dice al compilatore che dovrebbe restituire un valore poi continuare. resa è una parola chiave contesto ed è consentito solo all'interno di una dichiarazione iterativo. Un generatore è un modo semplice di crei una sorgente di dati IEnumerable. Il compilatore costruire una macchina a stati da questo codice e creare una classe anonima enumerabile. A quanto pare la parola resa non esiste in VB.NET. Ma è ancora possibile scrivere una classe che fa questo.

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
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top