views:

370

answers:

1

Does anyone have a function that will iterate through ever masterpage/sub masterpage that a content form belongs to, and iterate through each control of said masterpage/sub masterpage?

The reason why i ask is that i'm building up an increasingly confusing stack of masterpages and am starting to "lose" controls - i.e. not being able to find them because they're lost in the hierarchy.

Would be nice to have some function that will dump a tree of the hierarchy so i can locate my wayward controls.

+1  A: 

You can do this pretty easily using a recursive method. If you want to be fancy you can even use extension methods that takes some delegates as parameters for greater flexibility.

Implementing the method is as easy as dropping a new class in your App_Code folder:

Public Module ControlParser
    Sub New()
    End Sub
    <System.Runtime.CompilerServices.Extension> _
    Public Sub ForEachRecursive(ByVal ctrl As Control, ByVal callback As Action(Of Control), ByVal onMethodEnter As Action, ByVal onMethodLeave As Action)
        onMethodEnter.Invoke()
        
        If ctrl Is Nothing Then
            Exit Sub
        End If
        
        callback(ctrl)
        
        For Each curCtrl As Control In ctrl.Controls
            ForEachRecursive(curCtrl, callback, onMethodEnter, onMethodLeave)
        Next
        
        onMethodLeave.Invoke()
    End Sub
End Module

Utilizing this from inside your page to walk through all controls and print them out in a hierarchical view could be accomplished like so:

Private depth As Int32 = -1
Private sbOutput As New StringBuilder()
Private Const SPACES_PER_TAB As Int32 = 4

Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs)
    Me.ForEachRecursive(PrintControl, Function() System.Math.Max(System.Threading.Interlocked.Increment(depth),depth - 1), Function() System.Math.Max(System.Threading.Interlocked.Decrement(depth),depth + 1))
    //Output is a panel on the page
    output.Controls.Add(New LiteralControl(sbOutput.ToString()))
End Sub

Public Sub PrintControl(ByVal c As Control)
    sbOutput.Append(GetTabs(depth) + c.ClientID & "<br />")
End Sub

Public Function GetTabs(ByVal tabs As Int32) As [String]
    Return If(tabs < 1, String.Empty, New [String]("*"c, tabs * SPACES_PER_TAB).Replace("*", "&nbsp;"))
End Function

I appologize if the code looks funny, but I coded this in C# and used a converter. However, I was able to dump the actual VB code into my App_Code directory and confirm that it worked.

Hope this helps :)

Josh
its having issues with this line: Me.ForEachRecursive(PrintControl(), Function() System.Math.Max(System.Threading.Interlocked.Increment(depth), depth - 1), Function() System.Math.Max(System.Threading.Interlocked.Decrement(depth), depth + 1))printControl requires a control, but i'm not sure where to get that from..
NoCarrier
I notice that you put parenthesis after PrintControl. Remember that ForEachRecursive takes an Action<Control> delegate as the first parameter. When passing in a delegate as a parameter you only pass in the name of the function without parenthesis. In this way .Net only passes a reference to the function which it then calls back to with the appropriate parameters. You can read more about delegates here: http://www.developerfusion.com/article/5251/delegates-in-vbnet/
Josh