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
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 ?