TreeView, LINQ to SQL popolazione dati ricorsiva
-
09-09-2019 - |
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
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