0

In my project I have a setting called DriveLetter and I wish to insert the value of this setting in to the text of several controls on a form (replacing a placeholder).

I thought the easiest way to do this would be to loop through each control on the form and search for the placeholder, but through trial and error I have discovered that I can't do that (at least in the way I'm trying) because I make use of Containers, such as the SplitContainer and the Panel.

Below is what I have so far, which takes in to account the aforementioned SplitContainer and Panel containesr, but how can I amend this to loop through every control on the form without having to explicitly check if the current control is a type of container?

Private DRIVE_LETTER As String = My.Settings.DriveLetter

'**
' Handle form loading
''
Private Sub form_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load

    ReplaceDriveLetter(Me)

End Sub

'**
' Update the value of the <DRIVE_LETTER> text placehoder
''
Private Sub ReplaceDriveLetter(ByVal ctrlContainer As Control)

    For Each ctrl As Control In ctrlContainer.Controls

        If TypeOf ctrl Is SplitContainer Or TypeOf ctrl Is Panel Then
            ReplaceDriveLetter(ctrl)
        Else
            ctrl.Text = Replace(ctrl.Text, "<DRIVE_LETTER>", UCase(DRIVE_LETTER))
        End If

    Next ctrl

End Sub
David Gard
  • 11,225
  • 36
  • 115
  • 227
  • I'd recommend using a stack, and then if the current control contains controls, add all of these controls to the stack, and pop them if they don't contain controls. I can write an answer, I'll just need a few minutes. – Sastreen Jun 11 '15 at 11:23

2 Answers2

3

You can also use Control.HasChildren Property to check if a control contains one or more child controls.

As stated on MSDN, if the Controls collection has a Count greater than zero, the HasChildren property will return true. Accessing the HasChildren property does not force the creation of a Control.ControlCollection if the control has no children, so referencing this property can provide a performance benefit when walking a tree of controls.

So you can change your function in:

Private Sub ReplaceDriveLetter(ByVal ctrlContainer As Control)

    For Each ctrl As Control In ctrlContainer.Controls

        If ctrl.HasChildren Then
            ReplaceDriveLetter(ctrl)
        Else
            ctrl.Text = Replace(ctrl.Text, "<DRIVE_LETTER>", UCase(DRIVE_LETTER))
        End If

    Next ctrl

End Sub
tezzo
  • 10,858
  • 1
  • 25
  • 48
  • sorry if I put you on the wrong road with my example in: http://stackoverflow.com/questions/30776937/enable-all-linklabel-controls/30777029 ;) – tezzo Jun 11 '15 at 12:55
  • Oh, `HasChildern` = my new best friend! Thanks for pointing it out, the next beer is on me ;) – David Gard Jun 11 '15 at 13:02
1

This should do it, although obviously replace the text here with the DriveLetter (I can help with that if you'd like).

Private Sub ReplaceAllControlsOnForm()
    Dim stackOfControls As New Stack(Of Control)

    'add initial controls (all on form)
    For Each c As Control In Me.Controls
        stackOfControls.Push(c)
    Next

    'go until no controls are left
    While (stackOfControls.Count > 0)
        Dim currControl As Control = stackOfControls.Pop
        currControl.Text = "text here"
        'see if our control can contain controls
        If (currControl.Controls IsNot Nothing AndAlso currControl.Controls.Count > 0) Then
            'add all of these controls onto our stack
            For Each c As Control In currControl.Controls
                stackOfControls.Push(c)
            Next
        End If
    End While
End Sub
Sastreen
  • 597
  • 4
  • 13
  • Thanks for posting. I'm fine adding the drive letter in, but your code is generating an error on the line ` While (stackOfControls.Peek IsNot Nothing)` - InvalidOperationException was unhandled. – David Gard Jun 11 '15 at 12:33
  • @DavidGard Sorry, that worked for me but this is better I think (see edit). I changed it to just make sure the stack wasn't empty. – Sastreen Jun 11 '15 at 12:39
  • I've got my original solution working by including the line `If (currControl.Controls IsNot Nothing AndAlso currControl.Controls.Count > 0) Then`, rather then checking the `TypeOf` control as in my example. So not your full code, but your code contained the key. Thanks for the help. – David Gard Jun 11 '15 at 12:50
  • @DavidGard Excellent, OK. I'm glad your code is working and glad I could help. – Sastreen Jun 11 '15 at 12:53