Pergunta

Eu tenho um IEnumerable (do empregado) com uma relação ParentID / ChildID consigo mesma que eu posso vincular a um TreeView e ele preenche a hierarquia perfeitamente. No entanto, eu quero ser capaz de malha manualmente através de todos os registros e criar todos os nós de programação para que eu possa alterar os atributos para cada nó com base nos dados para que determinado item / nenhum.

Existe um tutorial lá fora, que explica como fazer isso? Eu já vi muitos que usam conjuntos de dados e datatables mas nenhum que mostram como fazê-lo em LINQ to SQL (IEnumerable)

UPDATE:

Aqui está como eu costumava fazer isso com um DataSet -. Eu simplesmente não consigo encontrar como fazer o mesmo com 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
Foi útil?

Solução

Se você só precisa encontrar uma maneira de enumerar a árvore que você pode implementar isso como um gerador, pode parecer estranho, você provavelmente está melhor com um recenseador definida pelo usuário, mas é essencialmente a mesma coisa.

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

O tipo de restrição, onde TEntity: IGetChildItems é apenas para significar que você precisa abstrato como descer a hierarquia. Sem o código acima não compilar.

Isto irá enumerar a árvore em uma primeira forma largura, que vai produzir o elemento pai primeiro, então é as crianças, e, em seguida, as crianças dessas crianças. Você pode facilmente personalizar o código acima para alcançar um comportamento diferente.

Editar:

O material de rendimento retorno diz ao compilador que ele deve retornar um valor, em seguida, continuar. rendimento é uma palavra-chave de contexto e só é permitido dentro de uma instrução iterativa. Um gerador é uma maneira simples de escrever uma fonte de dados IEnumerable. O compilador irá construir uma máquina de estado a partir deste código e criar uma classe anônima enumeráveis. Aparentemente, a palavra-chave yield não existe no VB.NET. Mas você ainda pode escrever uma classe que faz isso.

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
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top