Search code examples
vb.netienumerableredundancy

Enumerate all controls in a form (redundant)


I'm trying to enumerate all the controls in a form that satisfy a certain condition like the code beelow

Public Enum MethodSeachEnum
    StartsWith = 1
    EndsWith = 2
    Contains = 3
End Enum

Public Function GetAllControls(Control As Control, Key As String, MethodSeach As MethodSeachEnum, ControlType As Type, Optional UseTag As Boolean = True) As IEnumerable(Of Control)
    Dim controls = Control.Controls.Cast(Of Control)()

    Return (controls.SelectMany(Function(ctrl) GetAllControls(ctrl, Metodo)).Concat(controls).Where(Function(c)
            Select Case MethodSeach
                Case MetodoSeachEnum.EndsWith
                    If (UseTag) Then
                        Return c.Tag.ToString.ToUpper.EndsWith(Key.ToUpper) And c.GetType() Is ControlType 
                    Else
                        Return c.Name.ToUpper.EndsWith(Key.ToUpper) And c.GetType() Is ControlType 
                    End If
                Case MetodoSeachEnum.StartsWith
                    If (UseTag) Then
                        Return c.Tag.ToString.ToUpper.StartsWith(Key.ToUpper) And c.GetType() Is ControlType 
                    Else
                        Return c.Name.ToUpper.StartsWith(Key.ToUpper) And c.GetType() Is ControlType 
                    End If
                Case MetodoSeachEnum.Contains
                    If (UseTag) Then
                        Return c.Tag.ToString.ToUpper.Contains(Key.ToUpper) And c.GetType() Is ControlType 
                    Else
                        Return c.Name.ToUpper.Contains(Key.ToUpper) And c.GetType() Is ControlType 
                    End If
                Case Else
                    Return False
            End Select
        End Function))
End Function

Inside my form there is a GroupBox and inside that some TextBox. These TextBox are not returned and I'm not understanding why...

Here how I call this function

Dim ctrls = GetAllControls(FormTagliente, "txtQuote", MetodoSeachEnum.StartsWith, GetType(TextBox), False)

        For Each txt As TextBox In ctrls 

            ...

        Next

Solution

  • There is IMHO too few information to answer your question "why that doesn't work for your specific case"
    Also the GetAllControls with two argument is missing in your code maybe the problem lies there
    Anyway I toyed a little with your code (but haven't tested it so it's more a POC) and here's what I got :

    Enum SearchMethod
        StartsWith = 1
        EndsWith = 2
        Contains = 3
    End Enum
    
    Function GetAllControls(Of T As Control)(ctrl As Control, key As String, method As SearchMethod, Optional useTag As Boolean = True) As IEnumerable(Of T)
        ' TODO validate args
        Dim upperKey = key.ToUpper
    
        Dim searchPredicates() As Func(Of String, Boolean) = {
            Function(src, tgt) src.StartsWith(upperKey),
            Function(src, tgt) src.EndsWith(upperKey),
            Function(src, tgt) src.Contains(upperKey)
        }
        Dim ctrlSelector As Func(Of Control, String) = If(useTag, Function(c) c.Tag.ToString.ToUpper, Function(c) c.Name.ToUpper)
    
        Return GetAllControlsIterator(Of T)(ctrl, ctrlSelector, searchPredicates(CInt(method) - 1))
    End Function
    
    Private Iterator Function GetAllControlsIterator(Of T As Control)(ctrl As Control, ctrlSelector As Func(Of Control, String), searchPredicate As Func(Of String, Boolean)) As IEnumerable(Of T)
        For Each child In ctrl.Controls
            If searchPredicate(ctrlSelector(child)) AndAlso TypeOf child Is T Then Yield DirectCast(child, T)
    
            For Each grandChild In GetAllControlsIterator(Of T)(child, ctrlSelector, searchPredicate)
                Yield DirectCast(grandChild, T)
            Next
        Next
    End Function
    

    The idea was to separate the "construct the criteria logic" to the actual "loop, search, yield" one, using a generic constraint to force the targetType to be a Control (and having directly the "good" return type). I also find simpler to use an Iterator block but that's more personal
    Maybe that could help you solve your problem ?