3

TreeViewにデータバインドでき、階層を完全に設定できるParentID/ChildID関係を持つIEnumerable(Employeeの)があります。ただし、すべてのレコードを手動でループし、すべてのノードをプログラムで作成して、その特定のアイテム/なしのデータに基づいて各ノードの属性を変更できるようにしたいと考えています。

これを行う方法を説明するチュートリアルはありますか? データセットとデータテーブルを使用するものをたくさん見てきましたが、Linq to 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
4

1 に答える 1

3

ツリーを列挙する方法が必要な場合は、これをジェネレーターとして実装できます。奇妙に見えるかもしれません。ユーザー定義の列挙子を使用した方がよいでしょうが、基本的には同じです。

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はコンテキストキーワードであり、反復ステートメント内でのみ許可されます。ジェネレーターは、IEnumerableデータソースを作成する簡単な方法です。コンパイラは、このコードからステートマシンを構築し、列挙可能な匿名クラスを作成します。どうやらyieldキーワードは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
于 2009-02-26T07:07:53.520 に答える