web-dev-qa-db-ja.com

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)
21
JosephStyons

TryCast でGetTypeとCTypeダンスをスキップできます:

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

編集:NullReferenceExceptionsを無視するEvil拡張メソッドを考えても気が進まない場合:

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

TryCast(ctrl, CheckBox).ClearValue()
16
Mark Brackett

ここに、フォームのすべての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
8
Imran

なぜ1つのルーチンだけではないのですか

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

呼び出しを開始する階層のレベル(フォームレベルから単一のコンテナーまで)に関係なく、再帰することができます。

また、TextBoxコントロールでは、Textbox.Text = String.Empty

2
rjrapson
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
1
user3692282

私は似たようなことをしましたが、これは基本的に私がそれをやろうとした方法です。私が提案する唯一の変更は、メソッドをオーバーロードする代わりに、渡された型をコントロールにするだけで、GroupControl、Panel、または.Controlsプロパティを提供する他のコンテナコントロールに同じバージョンを使用できます。それ以外は、コントロールの「クリア」の定義はやや曖昧になる可能性があるため、Controlクラスに属するClear()メソッドはないため、各コントロールタイプの目的に応じてその意味を実装する必要があります。

1
theraccoonbear

ここでは、すべての内部コントロールに対して機能します。
他のコントロールをクリアする必要がある場合は追加します。

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

(CONTAINER)を自分の名前に置き換えます(フォーム、パネル、GROUPBOXの場合があります)
コントロールを含めた場所に注意してください。

1
ShoushouLebanon

これは、コントロールアレイが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
1
dmcgill50

私の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)
0
ElektroStudios