vb.net 循环遍历表单中的所有文本框,包括分组框内的文本框

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4673950/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 15:14:02  来源:igfitidea点击:

loop over all textboxes in a form, including those inside a groupbox

vb.netwinforms

提问by kodkod

I have several textboxes in a winform, some of them are inside a groupbox. I tried to loop over all textboxes in my form:

我在 winform 中有几个文本框,其中一些在 groupbox 内。我尝试遍历表单中的所有文本框:

For Each c As Control In Me.Controls
    If c.GetType Is GetType(TextBox) Then
        ' Do something
    End If
Next

But it seemed to skip those inside the groupbox and loop only over the other textboxes of the form. So I added another For Each loop for the groupbox textboxes:

但它似乎跳过了 groupbox 内的那些,并且只在表单的其他文本框上循环。所以我为 groupbox 文本框添加了另一个 For Each 循环:

For Each c As Control In GroupBox1.Controls
    If c.GetType Is GetType(TextBox) Then
        ' Do something
    End If
Next

I wonder: is there a way to loop over all textboxes in a form--including those inside a groupbox--with a single For Each loop? Or any better/more elegant way to do it?

我想知道:有没有办法用单个 For Each 循环遍历表单中的所有文本框——包括那些在 groupbox 中的文本框?或者有什么更好/更优雅的方式来做到这一点?

Thanks in advance.

提前致谢。

回答by Tim Schmelter

You can use this function, linqmight be a more elegant way.

您可以使用此功能,linq可能是一种更优雅的方式。

Dim allTxt As New List(Of Control)
For Each txt As TextBox In FindControlRecursive(allTxt, Me, GetType(TextBox))
   '....'
Next

Public Shared Function FindControlRecursive(ByVal list As List(Of Control), ByVal parent As Control, ByVal ctrlType As System.Type) As List(Of Control)
    If parent Is Nothing Then Return list
    If parent.GetType Is ctrlType Then
        list.Add(parent)
    End If
    For Each child As Control In parent.Controls
        FindControlRecursive(list, child, ctrlType)
    Next
    Return list
End Function

回答by JYelton

You'd want to do recursion, for example (pseudocode, since I do not know VB):

例如,您想要进行递归(伪代码,因为我不知道 VB):

Sub LoopControls (Control Container)
    if (Container has Controls)
        LoopControls(Container)
    For Each c As Control In Container
        if (Control is TextBox)
            // do stuff
End Sub

You would pass your form (me) to the sub initially, and it will traverse the controls in it looking for ones that contain more controls.

您最初会将表单 (me) 传递给 sub,它将遍历其中的控件以查找包含更多控件的控件。

Also check out this question: VB.NET - Iterating through controls in a container object

另请查看这个问题:VB.NET - Iterating through controls in a container object

回答by Reddog

You will need to use recursion. The following is a C# solution using an extension method and goes a little beyond the scope of your question but I just pulled it from our framework.

您将需要使用递归。以下是使用扩展方法的 C# 解决方案,有点超出您的问题范围,但我只是从我们的框架中提取它。

static partial class ControlExtensions
{
    public static void ApplyToMatchingChild(this Control parent, Action<Control> actionToApplyWhenFound, bool keepApplyingForever, params Func<Control, bool>[] matchingChildCriteria)
    {
        ControlEventHandler reapplyEventHandler = null;
        if (keepApplyingForever)
        {
            reapplyEventHandler = (s, e) =>
            {
                ApplyToMatchingChild(e.Control, actionToApplyWhenFound, keepApplyingForever, matchingChildCriteria);
            };
        }
        SearchForMatchingChildTypes(parent, actionToApplyWhenFound, reapplyEventHandler, matchingChildCriteria);
    }

    private static void SearchForMatchingChildTypes(Control control, Action<Control> actionToApplyWhenFound, ControlEventHandler reapplyEventHandler, params Func<Control, bool>[] matchingChildCriteria)
    {
        if (matchingChildCriteria.Any(criteria => criteria(control)))
        {
            actionToApplyWhenFound(control);
        }

        if (reapplyEventHandler != null)
        {
            control.ControlAdded += reapplyEventHandler;
        }

        if (control.HasChildren)
        {
            foreach (var ctl in control.Controls.Cast<Control>())
            {
                SearchForMatchingChildTypes(ctl, actionToApplyWhenFound, reapplyEventHandler, matchingChildCriteria);
            }
        }
    }
}

And to call:

并调用:

myControl.ApplyToMatchingChild(c => { /* Do Stuff to c */ return; }, false, c => c is TextBox);

That will apply a function to all child textboxes. You can use the keepApplyingForeverparameter to ensure that your function will be applied when child controls are later added. The function will also allow you to specify any number of matching criteria, for example, if the control is also a label or some other criteria.

这将对所有子文本框应用一个函数。您可以使用该keepApplyingForever参数来确保在以后添加子控件时应用您的函数。该函数还允许您指定任意数量的匹配条件,例如,如果控件也是标签或某些其他条件。

We actually use this as a neat way to call our dependency injection container for every UserControl added to our Form.

我们实际上使用它作为一种巧妙的方式来为每个添加到我们表单的 UserControl 调用我们的依赖注入容器。

I'm sure you shouldn't have much issue converting it to VB.NETtoo... Also, If you don't want the "keepApplyingForever" functionality, it should be easy enough to strip that out too.

我敢肯定,将其转换为 VB.NET也不会有太大问题...此外,如果您不想要“keepApplyingForever”功能,也应该很容易将其删除。

回答by PulseJet

If you don't care about the order (and I can't imagine a reason why you should) of the controls, you can do this iteratively in the following fashion (its quite straightforward, so I don't think any explanation is necessary). Should be much more efficient than any recursion, especially if you have many nested controls, though I doubt if the performance gain would be apparent.

如果您不关心控件的顺序(我无法想象您应该这样做的原因),您可以按以下方式迭代地执行此操作(它非常简单,所以我认为不需要任何解释)。应该比任何递归更有效,特别是如果您有许多嵌套控件,但我怀疑性能增益是否会很明显。

Public Function FindAllControlsIterative(ByRef parent As Control) As List(Of TextBox)
    Dim list As New List(Of TextBox)
    Dim ContainerStack As New Stack(Of Control)
    ContainerStack.Push(parent)
    While ContainerStack.Count > 0
        For Each child As Control In ContainerStack.Pop().Controls
            If child.HasChildren Then ContainerStack.Push(child)
            If child.GetType Is GetType(TextBox) Then list.Add(child)
        Next
    End While
    Return list
End Function