This is a class that allows you to iterate over collections that would normally require recursion. It's quite simple, and actually, is really handy.

Basically, you instantiate the class and then you can perform a For Each on the class which will enumerate through every element in the hierarchical structure.

Here are a couple very common uses:

  1. Enumerating Controls
    This is something you can run on your Form to get every control. Another way you could use it is if you only wanted every control in a Panel. You would just specify the Panel's Controls property in place of the Form's Controls. Since a Form derives from Control, you can simply specify the Form's instance as the first argument to the constructor. (As opposed to the TreeView example below.)
    Code:
    Dim iterator = New RecursiveIterator(Of Control, Control.ControlCollection) _
                                        (Me, Function(c) c.Controls)
    
    For Each c In iterator
        Console.WriteLine("Name: {0}", c.Name)
    Next
  2. Enumerating TreeViews
    This is a somewhat special case because a TreeView is not of type TreeNode. For this case, you would specify the starting collection instead of the actual TreeView.
    Code:
    Dim iterator = New RecursiveIterator(Of TreeNode, TreeNodeCollection) _
                                        (Me.TreeView1.Nodes, Function(n) n.Nodes)
    
    For Each n In iterator
        Console.WriteLine("Name: {0}, Level: {1}", n.Name, n.Level)
    Next
  3. Your custom classes
    You should find that this class works quite easily with your custom classes. Here is an example structure that this class could enumerate.
    Code:
    Public Class Person
    
        '//properties
        Private _children As PersonCollection
        Public ReadOnly Property Children() As PersonCollection
            Get
                Return Me._children
            End Get
        End Property
    
    End Class
    
    Public Class PersonCollection
        Inherits List(Of Person)
    
    End Class
    Code:
    Dim mom = New Person()
    Dim iterator = New RecursiveIterator(Of Person, PersonCollection) _
                                        (mom, Function(p) p.Children)
    
    For Each p In iterator
        '//... all of mom's children, grand-children, grand-grand children etc...
    Next

The trick is telling the class how to retrieve the collection of the element's children. This is done with a Func(Of T1, T2) delegate.

Here is the simple class:
Code:
''' <summary>
''' Represents a class that can enumerate through hierarchical based structures.
''' </summary>
''' <typeparam name="TElement">The type of the element.</typeparam>
''' <typeparam name="TSource">The type of the collection of elements.</typeparam>
Public Class RecursiveIterator(Of TElement, TSource As IEnumerable)
    Implements IEnumerable(Of TElement)

    '//fields
    Private elements As List(Of TElement)
    Private startingSource As TSource
    Private selector As Func(Of TElement, TSource)

    '//properties
    ''' <summary>
    ''' Gets the number of elements contained in the iterator.
    ''' </summary>
    Public ReadOnly Property Count() As Integer
        Get
            Return Me.elements.Count
        End Get
    End Property

    ''' <summary>
    ''' Gets the element at the specified index.
    ''' </summary>
    ''' <param name="index">The index of the item to retrieve.</param>
    Default Public ReadOnly Property Item(ByVal index As Integer) As TElement
        Get
            Return Me.elements(index)
        End Get
    End Property

    '//constructors
    ''' <summary>
    ''' Initializes a new instance of the 
    '''     <see cref="RecursiveIterator(Of TElement, TSource)">
    '''     RecursiveIterator(Of TElement, TSource)
    '''     </see>
    ''' class.
    ''' </summary>
    ''' <param name="startingSource">
    ''' The initial source from which the iterator will fill.
    ''' </param>
    ''' <param name="sourceSelector">
    ''' The selector that retrieves the enumerating
    ''' source from each element.
    ''' </param>
    Public Sub New(ByVal startingSource As TSource, _
                   ByVal sourceSelector As Func(Of TElement, TSource))

        Me.elements = New List(Of TElement)()
        Me.startingSource = startingSource
        Me.selector = sourceSelector

        '//fill the iterator
        Me.RecursivePopulate(Me.startingSource)
    End Sub

    ''' <summary>
    ''' Initializes a new instance of the 
    '''     <see cref="RecursiveIterator(Of TElement, TSource)">
    '''     RecursiveIterator(Of TElement, TSource)
    '''     </see>
    ''' class.
    ''' </summary>
    ''' <param name="startingElement">
    ''' The initial element from which the iterator will fill.
    ''' </param>
    ''' <param name="sourceSelector">
    ''' The selector that retrieves the enumerating
    ''' source from each element.
    ''' </param>
    Public Sub New(ByVal startingElement As TElement, _
                   ByVal sourceSelector As Func(Of TElement, TSource))
        Me.New(sourceSelector(startingElement), sourceSelector)
    End Sub

    '//methods
    Private Sub RecursivePopulate(ByVal collection As TSource)

        For Each element As TElement In collection
            Me.elements.Add(element)

            Me.RecursivePopulate(Me.selector(element))
        Next

    End Sub

    Private Function GetEnumeratorUntyped() As IEnumerator _
                     Implements IEnumerable.GetEnumerator

        Return Me.GetEnumerator()
    End Function

    ''' <summary>
    ''' Returns an enumerator that iterates through each <see cref="TElement">TElement</see>.
    ''' </summary>
    Public Function GetEnumerator() As IEnumerator(Of TElement) _
                    Implements IEnumerable(Of TElement).GetEnumerator

        Return Me.elements.GetEnumerator()
    End Function

End Class
Quote Originally Posted by *Note*
For anyone that cares, they should note that I purposely did not declare TSource with a constraint of IEnumerable(Of TElement) so that you wouldn't have to do AsEnumerable calls on these collections. Just know the compiler is not checking the type safety of these collections.
Feel free to implement the functionality to refresh the iterator so that it can be reused. As it stands, it gets populated once.