VB.NET - перебор элементов управления в объекте контейнера

У меня есть форма с кнопкой "Очистить".

Когда пользователь нажимает "Очистить", я хочу очистить значение всех видимых элементов в форме. В случае элементов управления дат я хочу сбросить их на текущую дату.

Все мои элементы управления содержатся на панели.

Прямо сейчас я делаю это с помощью приведенного ниже кода. Есть ли более простой способ, чем проверка вручную для каждого типа управления? Этот метод кажется чрезмерно громоздким.

Что еще хуже, чтобы рекурсивно очистить элементы управления внутри субконтейнеров (т. Е. Групповой блок на панели), я должен повторить весь монстр с перегруженной версией "GroupBox".

Изменить: Благодаря вашим предложениям приведенный ниже код значительно упрощен.

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: мне нравится ваше предложение, но когда я изменяю заявление на это:

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

Затем эта строка дает мне "Невозможно привести объект типа" ControlCollection "к типу" ControlCollection ".":

  ClearAllControls(panMid.Controls)

9 ответов

Решение

Вы можете пропустить танец GetType и CType с TryCast:

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

Это сэкономит вам около 10 строк.

Метод расширения класса Control должен содержать его в чистоте:

<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

Изменить: Если мысль о методах расширения Зла, которые игнорируют исключения NullReferenceException, не заставляет вас съеживаться:

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

TryCast(ctrl, CheckBox).ClearValue()

Вот код для получения всех элементов управления All GroupControls формы, и вы можете сделать что-то в элементе управления GroupBox

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

Почему бы просто не иметь одну рутину

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

Вы можете войти в него независимо от того, с какого уровня в иерархии вы начинаете вызов, от уровня формы до одного контейнера.

Кроме того, на элементах управления TextBox я использую Textbox.Text = String.Empty

Я сделал что-то похожее, и вот как я это делал. Единственное изменение, которое я могу предложить, - вместо перегрузки метода просто сделать передаваемый тип типа Control, и вы сможете использовать ту же версию для GroupBox, Panel или любого другого элемента управления контейнера, который предоставляет свойство.Controls. Кроме этого, я думаю, что определение "очистки" элемента управления может быть несколько двусмысленным, и поэтому нет метода Clear(), принадлежащего классу Control, поэтому вам необходимо реализовать то, что это означает для ваших целей для каждого типа элемента управления.

Это прямо из статьи, в которой обсуждаются методы, которые нужно использовать теперь, когда управляющие массивы покончили с переходом с VB6 на 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

Public Sub raz(lst As Control.ControlCollection, необязательный рекурсивный 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

Здесь это работает для всех внутренних контролей.
Добавьте, если какие-либо другие элементы управления вам нужно очистить.

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
For Each c In CONTAINER.Controls
    If TypeOf c Is TextBox Then
        c.Text = ""
    End If
Next

Замените (КОНТЕЙНЕР) на свое имя (это может быть ФОРМА, ПАНЕЛЬ, ГРУППА)
Обратите внимание, что вы включили свои элементы управления в.

Это может помочь в будущем развитии...

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

Я представляю тебе мой ControlIterator Учебный класс

Источник: http://pastebin.com/dubt4nPG

Некоторые примеры использования:

 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)
Другие вопросы по тегам