JosephStyons
JosephStyons

Reputation: 58685

VB.NET - Iterating through controls in a container object

I have a form with a "Clear" button.

When the user clicks "Clear", I want to clear the value of all the visible elements on the form. In the case of date controls, I want to reset them to the current date.

All of my controls are contained on a Panel.

Right now, I'm doing this with the below code. Is there an easier way than manually checking for each control type? This method seems excessively unwieldy.

To make matters worse, in order to recursively clear controls inside sub-containers (i.e., a group box within the panel) I have to repeat the whole monster with an overloaded "GroupBox" version.

Edit: Thanks to your suggestions, the below code is greatly simplified.

Private Sub btnClear_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnClear.Click
    'User clicks Clear, so clear all the controls within this panel
    ClearAllControls(panMid, True) 'True indicates that yes, i want to recurse through sub-containers
End Sub

ClearAllControls(ByRef container As Panel, Optional Recurse As Boolean = True)   
  'Clear all of the controls within the container object
  'If "Recurse" is true, then also clear controls within any sub-containers
  Dim ctrl As Control
  For Each ctrl In container.Controls
      If (ctrl.GetType() Is GetType(TextBox)) Then
          Dim txt As TextBox = CType(ctrl, TextBox)
          txt.Text = ""
      End If
      If (ctrl.GetType() Is GetType(CheckBox)) Then
          Dim chkbx As CheckBox = CType(ctrl, CheckBox)
          chkbx.Checked = False
      End If
      If (ctrl.GetType() Is GetType(ComboBox)) Then
          Dim cbobx As ComboBox = CType(ctrl, ComboBox)
          cbobx.SelectedIndex = -1
      End If
      If (ctrl.GetType() Is GetType(DateTimePicker)) Then
          Dim dtp As DateTimePicker = CType(ctrl, DateTimePicker)
          dtp.Value = Now()
      End If

      If Recurse Then
          If (ctrl.GetType() Is GetType(Panel)) Then
              Dim pnl As Panel = CType(ctrl, Panel)
              ClearAllControls(pnl, Recurse)
          End If
          If ctrl.GetType() Is GetType(GroupBox) Then
              Dim grbx As GroupBox = CType(ctrl, GroupBox)
              ClearAllControls(grbx, Recurse)
          End If
      End If
  Next
End Sub

@Theraccoonbear: I like your suggestion, but when I change the declaration to this:

Private Sub ClearAllControls(ByRef controls As ControlCollection, Optional ByVal Recurse As Boolean = True)

Then this line gives me "Unable to cast object of type 'ControlCollection' to type 'ControlCollection'.":

  ClearAllControls(panMid.Controls)

Upvotes: 22

Views: 103078

Answers (10)

user14410512
user14410512

Reputation: 1

This May Help in Future Development ...

GetAllButtons(Me)

Public Sub GetAllButtons(ByRef forms As Object)
    Dim list As New List(Of Button)
    Dim iIndx As Integer
    For Each c In forms.Controls
        For iIndx = 0 To forms.Controls.Count - 1
            If (TypeOf forms.Controls(iIndx) Is Button) Then
                list.Add(forms.Controls(iIndx))
            End If
            If (TypeOf forms.controls(iIndx) Is Panel) Then
                For Each cntrl As Control In forms.controls(iIndx).Controls
                    If TypeOf cntrl Is Button Then
                        list.Add(cntrl)
                    End If
                Next
            End If
        Next
    Next

Button(list.ToArray)

End Sub

Public Sub Button(btn() As Button)
    For Each bt In btn
       Do Something with Buttons
    next
End Sub

Upvotes: 0

user3692282
user3692282

Reputation: 11

Public Sub raz(lst As Control.ControlCollection, Optional recursive As Boolean = True)
    For Each ctrl As Control In lst
        If TypeOf ctrl Is TextBox Then
            CType(ctrl, TextBox).Clear()
        End If

        If TypeOf ctrl Is MaskedTextBox Then
            CType(ctrl, MaskedTextBox).Clear()
        End If

        If TypeOf ctrl Is ComboBox Then
            CType(ctrl, ComboBox).SelectedIndex = -1
        End If

        If TypeOf ctrl Is DateTimePicker Then
            Dim dtp As DateTimePicker = CType(ctrl, DateTimePicker)
            dtp.CustomFormat = " "
        End If

        If TypeOf ctrl Is CheckedListBox Then
            Dim clbox As CheckedListBox = CType(ctrl, CheckedListBox)
            For i As Integer = 0 To clbox.Items.Count - 1
                clbox.SetItemChecked(i, False)
            Next
        End If

        If TypeOf ctrl Is RadioButton Then
            CType(ctrl, RadioButton).Checked = False

        End If

        If recursive Then
            If TypeOf ctrl Is GroupBox Then
                raz(CType(ctrl, GroupBox).Controls)
            End If
        End If
    Next
End Sub

Upvotes: 1

ElektroStudios
ElektroStudios

Reputation: 20464

I present you my ControlIterator Class

Source: http://pastebin.com/dubt4nPG

Some usage examples:

 ControlIterator.Disable(CheckBox1)

 ControlIterator.Enable({CheckBox1, CheckBox2})

 ControlIterator.Check(Of CheckBox)(Me)

 ControlIterator.Uncheck(Of CheckBox)(Me.GroupBox1)

 ControlIterator.Hide(Of CheckBox)("1")

 ControlIterator.PerformAction(Of CheckBox)(Sub(ctrl As CheckBox) ctrl.Visible = True)

 ControlIterator.AsyncPerformAction(RichTextBox1,
                                    Sub(rb As RichTextBox)
                                        For n As Integer = 0 To 9
                                            rb.AppendText(CStr(n))
                                        Next
                                    End Sub)

 ControlIterator.PerformAction(Me.Controls, Sub(c As Control)
                                                c.BackColor = Color.Green
                                            End Sub)

Upvotes: 0

dmcgill50
dmcgill50

Reputation: 540

This comes straight from an article discussing techniques to use now that Control Arrays have been done away with going from VB6 to VB.NET.

Private Sub ClearForm(ByVal ctrlParent As Control)
    Dim ctrl As Control
    For Each ctrl In ctrlParent.Controls
        If TypeOf ctrl Is TextBox Then
           ctrl.Text = ""
        End If
        ' If the control has children, 
        ' recursively call this function
        If ctrl.HasChildren Then
            ClearForm(ctrl)
        End If
    Next
End Sub

Upvotes: 1

Imran
Imran

Reputation: 111

here is the code to get all control of a Form's All GroupControls and you can do something in the GroupBox Control

Private Sub GetControls()
    For Each GroupBoxCntrol As Control In Me.Controls
        If TypeOf GroupBoxCntrol Is GroupBox Then
            For Each cntrl As Control In GroupBoxCntrol.Controls
                'do somethin here

            Next
        End If

    Next
End Sub

Upvotes: 11

Sekhar Babu
Sekhar Babu

Reputation: 11

Here it works for all inner controls.
Add if any other controls do you need to clear.

Private Sub ClearAll()
    Try
        For Each ctrl As Control In Me.Controls
            If ctrl.[GetType]().Name = "Panel" Then
                ClearControls(ctrl)
            End If

            If ctrl.[GetType]().Name = "GroupBox" Then
                ClearControls(ctrl)
            End If
            If ctrl.[GetType]().Name = "ComboBox" Then
                Dim tb As ComboBox = TryCast(ctrl, ComboBox)
                tb.SelectedText = ""
            End If


            If ctrl.[GetType]().Name = "TabControl" Then
                ClearControls(ctrl)
            End If

            If ctrl.[GetType]().Name = "TextBox" Then
                Dim tb As TextBox = TryCast(ctrl, TextBox)
                tb.Clear()
            End If

            If ctrl.[GetType]().Name = "RadioButton" Then
                Dim tb As RadioButton = TryCast(ctrl, RadioButton)
                tb.Checked = False
            End If

            If ctrl.[GetType]().Name = "CheckBox" Then
                Dim tb As CheckBox = TryCast(ctrl, CheckBox)
                tb.Checked = False
            End If

            If ctrl.[GetType]().Name = "ComboBox" Then
                Dim tb As ComboBox = TryCast(ctrl, ComboBox)
                tb.SelectedIndex = 0
            End If

            If ctrl.[GetType]().Name = "RichTextBox" Then
                Dim tb As RichTextBox = TryCast(ctrl, RichTextBox)
                tb.Clear()

            End If
        Next
    Catch ex As Exception
        MessageBox.Show(ex.Message, "Error Message", MessageBoxButtons.OK, MessageBoxIcon.Error)
    End Try
End Sub


Private Sub ClearControls(ByVal Type As Control)

    Try
        For Each ctrl As Control In Type.Controls

            If ctrl.[GetType]().Name = "TextBox" Then
                Dim tb As TextBox = TryCast(ctrl, TextBox)
                tb.Clear()
            End If

            If ctrl.[GetType]().Name = "Panel" Then
                ClearControls(ctrl)
            End If

            If ctrl.[GetType]().Name = "GroupBox" Then
                ClearControls(ctrl)
            End If

            If ctrl.[GetType]().Name = "TabPage" Then
                ClearControls(ctrl)
            End If

            If ctrl.[GetType]().Name = "ComboBox" Then
                Dim tb As ComboBox = TryCast(ctrl, ComboBox)
                tb.SelectedText = ""
            End If

            If ctrl.[GetType]().Name = "RadioButton" Then
                Dim tb As RadioButton = TryCast(ctrl, RadioButton)
                tb.Checked = False
            End If

            If ctrl.[GetType]().Name = "CheckBox" Then
                Dim tb As CheckBox = TryCast(ctrl, CheckBox)
                tb.Checked = False
            End If

            If ctrl.[GetType]().Name = "RichTextBox" Then
                Dim tb As RichTextBox = TryCast(ctrl, RichTextBox)
                tb.Clear()

            End If
        Next
    Catch ex As Exception
        MessageBox.Show(ex.Message, "Error Message", MessageBoxButtons.OK, MessageBoxIcon.Error)
    End Try
End Sub

Upvotes: 1

rjrapson
rjrapson

Reputation: 1997

Why not just have one routine

ClearAllControls(ByRef container As Control, Optional ByVal Recurse As Boolean = True)

You can recurse into it regardless of what level in the hierarchy you begin the call, from the form level down to a single container.

Also, on the TextBox controls, I use Textbox.Text = String.Empty

Upvotes: 2

ShoushouLebanon
ShoushouLebanon

Reputation: 11

For Each c In CONTAINER.Controls
    If TypeOf c Is TextBox Then
        c.Text = ""
    End If
Next

Replace the (CONTAINER) by the name of yours (it may be a FORM, a PANEL, a GROUPBOX)
Pay attention to which you had included your controls in.

Upvotes: 1

Mark Brackett
Mark Brackett

Reputation: 85655

You can skip the GetType and CType dance with TryCast:

Dim dtp as DateTimePicker = TryCast(ctrl, DateTimePicker)
If dtp IsNot Nothing then dtp.Value = Now()

That'll save you about 10 lines.

An extension method off the Control class should keep it pretty tidy:

<Extension()> _
Public Shared Sub ClearValue(c as Control, recursive as Boolean)
   Dim dtp as DateTimePicker = TryCast(c, DateTimePicker)
   If dtp IsNot Nothing Then dtp.Value = Now()
   ' Blah, Blah, Blah
End Sub

Edit: If the thought of Evil extension methods that ignore NullReferenceExceptions don't make you cringe:

<Extension()> _
Public Shared Sub ClearValue(c as CheckBox)
   If c IsNot Nothing Then c.Checked = False
End Sub

TryCast(ctrl, CheckBox).ClearValue()

Upvotes: 18

theraccoonbear
theraccoonbear

Reputation: 4337

I've done something similar and this is basically how I went about doing it. The only change I might suggest would be instead of overloading the method, just make the passed in type a Control and you can use the same version for GroupBox, Panel, or any other container control that provides a .Controls property. Other than that, I think the definition of "clearing" a control can be somewhat ambiguous and thus there's no Clear() method belonging to the Control class so you need to implement what that means for your purposes for each control type.

Upvotes: 1

Related Questions