如何获取特定类型(按钮/文本框)的Windows窗体窗体的所有子控件?

时间:2022-08-17 15:54:36

I need to get all controls on a form that are of type x. I'm pretty sure I saw that code once in the past that used something like this:

我需要在x类型的表单上获得所有控件。

dim ctrls() as Control
ctrls = Me.Controls(GetType(TextBox))

I know I can iterate over all controls getting children using a recursive function, but is there something easier or more straightforward, maybe like the following?

我知道我可以遍历使用递归函数获取子控件的所有控件,但是是否有更简单或更直接的方法,比如下面的方法?

Dim Ctrls = From ctrl In Me.Controls Where ctrl.GetType Is Textbox

23 个解决方案

#1


181  

Here's another option for you. I tested it by creating a sample application, I then put a GroupBox and a GroupBox inside the initial GroupBox. Inside the nested GroupBox I put 3 TextBox controls and a button. This is the code I used (even includes the recursion you were looking for)

这是另一个选择。我通过创建一个示例应用程序来测试它,然后在初始的GroupBox中放入一个GroupBox和一个GroupBox。在嵌套的GroupBox中,我放置了3个文本框控件和一个按钮。这是我使用的代码(甚至包括您要查找的递归)

public IEnumerable<Control> GetAll(Control control,Type type)
{
    var controls = control.Controls.Cast<Control>();

    return controls.SelectMany(ctrl => GetAll(ctrl,type))
                              .Concat(controls)
                              .Where(c => c.GetType() == type);
}

To test it in the form load event I wanted a count of all controls inside the initial GroupBox

要在form load事件中测试它,我需要在初始GroupBox中对所有控件进行计数。

private void Form1_Load(object sender, EventArgs e)
{
    var c = GetAll(this,typeof(TextBox));
    MessageBox.Show("Total Controls: " + c.Count());
}

And it returned the proper count each time, so I think this will work perfectly for what you're looking for :)

它每次都返回正确的计数,所以我认为这对你所寻找的是非常有效的:)

#2


28  

In C# (since you tagged it as such) you could use a LINQ expression like this:

在c#中(既然您这样标记它),您可以使用如下的LINQ表达式:

List<Control> c = Controls.OfType<TextBox>().Cast<Control>().ToList();

Edit for recursion:

递归编辑:

In this example, you first create the list of controls and then call a method to populate it. Since the method is recursive, it doesn't return the list, it just updates it.

在本例中,首先创建控件列表,然后调用一个方法来填充它。由于该方法是递归的,所以它不返回列表,而是更新列表。

List<Control> ControlList = new List<Control>();
private void GetAllControls(Control container)
{
    foreach (Control c in container.Controls)
    {
        GetAllControls(c);
        if (c is TextBox) ControlList.Add(c);
    }
}

It may be possible to do this in one LINQ statement using the Descendants function, though I am not as familiar with it. See this page for more information on that.

可能可以在一个LINQ语句中使用子类函数来实现这一点,尽管我对它不是很熟悉。有关这方面的更多信息,请参见此页。

Edit 2 to return a collection:

编辑2以返回一个集合:

As @ProfK suggested, a method that simply returns the desired controls is probably better practice. To illustrate this I have modified the code as follows:

正如@ProfK所建议的,简单地返回所需控件的方法可能是更好的实践。为了说明这一点,我修改了代码如下:

private IEnumerable<Control> GetAllTextBoxControls(Control container)
{
    List<Control> controlList = new List<Control>();
    foreach (Control c in container.Controls)
    {
        controlList.AddRange(GetAllTextBoxControls(c));
        if (c is TextBox)
            controlList.Add(c);
    }
    return controlList;
}

#3


12  

This is an improved version of the recursive GetAllControls() that actually works on private vars:

这是递归GetAllControls()的改进版本,它实际上适用于私有vars:

    private void Test()
    {
         List<Control> allTextboxes = GetAllControls(this);
    }
    private List<Control> GetAllControls(Control container, List<Control> list)
    {
        foreach (Control c in container.Controls)
        {
            if (c is TextBox) list.Add(c);
            if (c.Controls.Count > 0)
                list = GetAllControls(c, list);
        }

        return list;
    }
    private List<Control> GetAllControls(Control container)
    {
        return GetAllControls(container, new List<Control>());
    }

#4


8  

I combined a bunch of the previous ideas into one extension method. The benefits here are that you get the correctly typed enumerable back, plus inheritance is handled correctly by OfType().

我把以前的一些想法组合成一个扩展方法。这里的好处是您可以得到正确类型的可枚举值,并且继承可以由OfType()正确处理。

public static IEnumerable<T> FindAllChildrenByType<T>(this Control control)
{
    IEnumerable<Control> controls = control.Controls.Cast<Control>();
    return controls
        .OfType<T>()
        .Concat<T>(controls.SelectMany<Control, T>(ctrl => FindAllChildrenByType<T>(ctrl)));
}

#5


7  

You can use a LINQ query to do this. This will query everything on the form that is type TextBox

您可以使用LINQ查询来实现这一点。这将查询输入TextBox的窗体上的所有内容

var c = from controls in this.Controls.OfType<TextBox>()
              select controls;

#6


5  

It might be the ancient technique, but it works like charm. I used recursion to change the color of all labels of the control. It works great.

这可能是一种古老的技术,但它就像魅力一样发挥作用。我使用递归来改变控件的所有标签的颜色。它的工作原理。

internal static void changeControlColour(Control f, Color color)
{
    foreach (Control c in f.Controls)
    {

        // MessageBox.Show(c.GetType().ToString());
        if (c.HasChildren)
        {
            changeControlColour(c, color);
        }
        else
            if (c is Label)
            {
                Label lll = (Label)c;
                lll.ForeColor = color;
            }
    }
}

#7


4  

I'd like to amend PsychoCoders answer: as the user wants to get all controls of a certain type we could use generics in the following way:

我想修改一下心理编码员的回答:由于用户想要获得某种类型的所有控件,我们可以用以下方式使用泛型:

    public IEnumerable<T> FindControls<T>(Control control) where T : Control
    {
        // we can't cast here because some controls in here will most likely not be <T>
        var controls = control.Controls.Cast<Control>();

        return controls.SelectMany(ctrl => FindControls<T>(ctrl))
                                  .Concat(controls)
                                  .Where(c => c.GetType() == typeof(T)).Cast<T>();
    }

This way, we can call the function as follows:

这样,我们就可以把函数称为:

private void Form1_Load(object sender, EventArgs e)
{
    var c = FindControls<TextBox>(this);
    MessageBox.Show("Total Controls: " + c.Count());
}

#8


3  

Don't forget that you can also have a TextBox within other controls other than container controls too. You can even add a TextBox to a PictureBox.

不要忘记除了容器控件之外,在其他控件中也可以有一个文本框。你甚至可以在图片框中添加一个文本框。

So you also need to check if

所以你还需要检查一下

someControl.HasChildren = True

in any recursive function.

在任何一个递归函数。

This is the result I had from a layout to test this code:

这是我从布局中得到的测试代码的结果:

TextBox13   Parent = Panel5
TextBox12   Parent = Panel5
TextBox9   Parent = Panel2
TextBox8   Parent = Panel2
TextBox16   Parent = Panel6
TextBox15   Parent = Panel6
TextBox14   Parent = Panel6
TextBox10   Parent = Panel3
TextBox11   Parent = Panel4
TextBox7   Parent = Panel1
TextBox6   Parent = Panel1
TextBox5   Parent = Panel1
TextBox4   Parent = Form1
TextBox3   Parent = Form1
TextBox2   Parent = Form1
TextBox1   Parent = Form1
tbTest   Parent = myPicBox

Try this with one Button and one RichTextBox on a form.

试着在表单上使用一个按钮和一个RichTextBox。

Option Strict On
Option Explicit On
Option Infer Off

Public Class Form1

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

        Dim pb As New PictureBox
        pb.Name = "myPicBox"
        pb.BackColor = Color.Goldenrod
        pb.Size = New Size(100, 100)
        pb.Location = New Point(0, 0)
        Dim tb As New TextBox
        tb.Name = "tbTest"
        pb.Controls.Add(tb)
        Me.Controls.Add(pb)

        Dim textBoxList As New List(Of Control)
        textBoxList = GetAllControls(Of TextBox)(Me)

        Dim sb As New System.Text.StringBuilder
        For index As Integer = 0 To textBoxList.Count - 1
            sb.Append(textBoxList.Item(index).Name & "   Parent = " & textBoxList.Item(index).Parent.Name & System.Environment.NewLine)
        Next

        RichTextBox1.Text = sb.ToString
    End Sub

    Private Function GetAllControls(Of T)(ByVal searchWithin As Control) As List(Of Control)

        Dim returnList As New List(Of Control)

        If searchWithin.HasChildren = True Then
            For Each ctrl As Control In searchWithin.Controls
                If TypeOf ctrl Is T Then
                    returnList.Add(ctrl)
                End If
                returnList.AddRange(GetAllControls(Of T)(ctrl))
            Next
        ElseIf searchWithin.HasChildren = False Then
            For Each ctrl As Control In searchWithin.Controls
                If TypeOf ctrl Is T Then
                    returnList.Add(ctrl)
                End If
                returnList.AddRange(GetAllControls(Of T)(ctrl))
            Next
        End If
        Return returnList
    End Function

End Class

#9


2  

Using reflection:

使用反射:

// Return a list with all the private fields with the same type
List<T> GetAllControlsWithTypeFromControl<T>(Control parentControl)
{
    List<T> retValue = new List<T>();
    System.Reflection.FieldInfo[] fields = parentControl.GetType().GetFields(System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
    foreach (System.Reflection.FieldInfo field in fields)
    {
      if (field.FieldType == typeof(T))
        retValue.Add((T)field.GetValue(parentControl));
    }
}

List<TextBox> ctrls = GetAllControlsWithTypeFromControl<TextBox>(this);

#10


1  

Here is the Solution.

这是解决方案。

https://*.com/a/19224936/1147352

https://*.com/a/19224936/1147352

I have written this piece of code and selected only the panels, you can add more switches or ifs. in it

我已经编写了这段代码并只选择了面板,您可以添加更多的开关或ifs。在这

#11


1  

public List<Control> GetAllChildControls(Control Root, Type FilterType = null)
{
    List<Control> AllChilds = new List<Control>();
    foreach (Control ctl in Root.Controls) {
        if (FilterType != null) {
            if (ctl.GetType == FilterType) {
                AllChilds.Add(ctl);
            }
        } else {
            AllChilds.Add(ctl);
        }
        if (ctl.HasChildren) {
            GetAllChildControls(ctl, FilterType);
        }
    }
    return AllChilds;
}

#12


1  

Here is my extension method for Control, using LINQ, as an adaptation of @PsychoCoder version:

以下是我的控制扩展方法,使用LINQ作为@PsychoCoder版本的改编:

It takes a list of type instead that allows you to not need multiple calls of GetAll to get what you want. I currently use it as an overload version.

它采用了一个类型列表,允许您不需要多次GetAll调用就可以得到您想要的。我目前使用它作为一个重载版本。

public static IEnumerable<Control> GetAll(this Control control, IEnumerable<Type> filteringTypes)
{
    var ctrls = control.Controls.Cast<Control>();

    return ctrls.SelectMany(ctrl => GetAll(ctrl, filteringTypes))
                .Concat(ctrls)
                .Where(ctl => filteringTypes.Any(t => ctl.GetType() == t));
}

Usage:

用法:

//   The types you want to select
var typeToBeSelected = new List<Type>
{
    typeof(TextBox)
    , typeof(MaskedTextBox)
    , typeof(Button)
};

//    Only one call
var allControls = MyControlThatContainsOtherControls.GetAll(typeToBeSelected);

//    Do something with it
foreach(var ctrl in allControls)
{
    ctrl.Enabled = true;
}

#13


1  

   IEnumerable<Control> Ctrls = from Control ctrl in Me.Controls where ctrl is TextBox | ctrl is GroupBox select ctr;

Lambda Expressions

Lambda表达式

IEnumerable<Control> Ctrls = Me.Controls.Cast<Control>().Where(c => c is Button | c is GroupBox);

#14


0  

I modified from @PsychoCoder. All controls could be found now (include nested).

我从@PsychoCoder修改。现在可以找到所有控件(包括嵌套控件)。

public static IEnumerable<T> GetChildrens<T>(Control control)
{
  var type = typeof (T);

  var allControls = GetAllChildrens(control);

  return allControls.Where(c => c.GetType() == type).Cast<T>();
}

private static IEnumerable<Control> GetAllChildrens(Control control)
{
  var controls = control.Controls.Cast<Control>();
  return controls.SelectMany(c => GetAllChildrens(c))
    .Concat(controls);
}

#15


0  

This may work:

这可能工作:

Public Function getControls(Of T)() As List(Of T)
    Dim st As New Stack(Of Control)
    Dim ctl As Control
    Dim li As New List(Of T)

    st.Push(Me)

    While st.Count > 0
        ctl = st.Pop
        For Each c In ctl.Controls
            st.Push(CType(c, Control))
            If c.GetType Is GetType(T) Then
                li.Add(CType(c, T))
            End If
        Next
    End While

    Return li
End Function

I think the function to get all controls you are talking about is only available to WPF.

我认为,您所讨论的所有控件的功能只适用于WPF。

#16


0  

Here is a tested and working generic solution:

这里有一个经过测试的通用解决方案:

I have a large number UpDownNumeric controls, some in the main form, some in groupboxes within the form. I want only the one last selected control to change back-color to green, for which I first set all others to white, using this method: (can also expand to grandchildren)

我有大量的UpDownNumeric控件,有些在主窗体中,有些在窗体的分组框中。我只希望最后选中的控件将背景颜色改为绿色,为此我首先将其他控件设置为白色,使用此方法:(也可以扩展到孙辈)

    public void setAllUpDnBackColorWhite()
    {
        //To set the numericUpDown background color of the selected control to white: 
        //and then the last selected control will change to green.

        foreach (Control cont in this.Controls)
        {
           if (cont.HasChildren)
            {
                foreach (Control contChild in cont.Controls)
                    if (contChild.GetType() == typeof(NumericUpDown))
                        contChild.BackColor = Color.White;
            }
            if (cont.GetType() == typeof(NumericUpDown))
                cont.BackColor = Color.White;
       }
    }   

#17


0  

You can try this if you want :)

如果你想试试这个:

    private void ClearControls(Control.ControlCollection c)
    {
        foreach (Control control in c)
        {
            if (control.HasChildren)
            {
                ClearControls(control.Controls);
            }
            else
            {
                if (control is TextBox)
                {
                    TextBox txt = (TextBox)control;
                    txt.Clear();
                }
                if (control is ComboBox)
                {
                    ComboBox cmb = (ComboBox)control;
                    if (cmb.Items.Count > 0)
                        cmb.SelectedIndex = -1;
                }

                if (control is CheckBox)
                {
                    CheckBox chk = (CheckBox)control;
                    chk.Checked = false;
                }

                if (control is RadioButton)
                {
                    RadioButton rdo = (RadioButton)control;
                    rdo.Checked = false;
                }

                if (control is ListBox)
                {
                    ListBox listBox = (ListBox)control;
                    listBox.ClearSelected();
                }
            }
        }
    }
    private void btnClear_Click(object sender, EventArgs e)
    {
        ClearControls((ControlCollection)this.Controls);
    }

#18


0  

Although several other users have posted adequate solutions, I'd like to post a more general approach that may be more useful.

虽然其他几个用户已经发布了适当的解决方案,但是我希望发布一个更通用的方法,这可能更有用。

This is largely based on JYelton's response.

这主要是基于JYelton的反应。

public static IEnumerable<Control> AllControls(
    this Control control, 
    Func<Control, Boolean> filter = null) 
{
    if (control == null)
        throw new ArgumentNullException("control");
    if (filter == null)
        filter = (c => true);

    var list = new List<Control>();

    foreach (Control c in control.Controls) {
        list.AddRange(AllControls(c, filter));
        if (filter(c))
            list.Add(c);
    }
    return list;
}

#19


0  

    public static IEnumerable<T> GetAllControls<T>(this Control control) where T : Control
    {
        foreach (Control c in control.Controls)
        {
            if (c is T)
                yield return (T)c;
            foreach (T c1 in c.GetAllControls<T>())
                yield return c1;
        }
    }

#20


0  

    public IEnumerable<T> GetAll<T>(Control control) where T : Control
    {
        var type = typeof(T);
        var controls = control.Controls.Cast<Control>().ToArray();
        foreach (var c in controls.SelectMany(GetAll<T>).Concat(controls))
            if (c.GetType() == type) yield return (T)c;
    }

#21


0  

A clean and easy solution (C#):

一个干净简单的解决方案(c#):

static class Utilities {
    public static List<T> GetAllControls<T>(this Control container) where T : Control {
        List<T> controls = new List<T>();
        if (container.Controls.Count > 0) {
            controls.AddRange(container.Controls.OfType<T>());
            foreach (Control c in container.Controls) {
                controls.AddRange(c.GetAllControls<T>());
            }
        }

        return controls;
    }
}

Get all textboxes:

得到所有文本框:

List<TextBox> textboxes = myControl.GetAllControls<TextBox>();

#22


0  

Here is my Extension method. It's very efficient and is lazy.

这是我的扩展方法。它非常高效而且懒惰。

Usage:

用法:

var checkBoxes = tableLayoutPanel1.FindChildControlsOfType<CheckBox>();

foreach (var checkBox in checkBoxes)
{
    checkBox.Checked = false;
}

The code is:

的代码是:

public static IEnumerable<TControl> FindChildControlsOfType<TControl>(this Control control) where TControl : Control
    {
        foreach (var childControl in control.Controls.Cast<Control>())
        {
            if (childControl.GetType() == typeof(TControl))
            {
                yield return (TControl)childControl;
            }
            else
            {
                foreach (var next in FindChildControlsOfType<TControl>(childControl))
                {
                    yield return next;
                }
            }
        }
    }

#23


0  

For anyone looking for a VB version of Adam's C# code written as an extension of the Control class:

对于任何想要寻找一个VB版本的Adam的c#代码,作为控件类的扩展:

''' <summary>Collects child controls of the specified type or base type within the passed control.</summary>
''' <typeparam name="T">The type of child controls to include. Restricted to objects of type Control.</typeparam>
''' <param name="Parent">Required. The parent form control.</param>
''' <returns>An object of type IEnumerable(Of T) containing the control collection.</returns>
''' <remarks>This method recursively calls itself passing child controls as the parent control.</remarks>
<Extension()>
Public Function [GetControls](Of T As Control)(
    ByVal Parent As Control) As IEnumerable(Of T)

    Dim oControls As IEnumerable(Of Control) = Parent.Controls.Cast(Of Control)()
    Return oControls.SelectMany(Function(c) GetControls(Of T)(c)).Concat(oControls.Where(Function(c) c.GetType() Is GetType(T) Or c.GetType().BaseType Is GetType(T))
End Function

NOTE: I've added BaseType matching for any derived custom controls. You can remove this or even make it an optional parameter if you wish.

注意:我已经为任何派生自定义控件添加了BaseType匹配。您可以删除它,甚至可以将它设置为可选参数。

Usage

使用

Dim oButtons As IEnumerable(Of Button) = Me.GetControls(Of Button)()

#1


181  

Here's another option for you. I tested it by creating a sample application, I then put a GroupBox and a GroupBox inside the initial GroupBox. Inside the nested GroupBox I put 3 TextBox controls and a button. This is the code I used (even includes the recursion you were looking for)

这是另一个选择。我通过创建一个示例应用程序来测试它,然后在初始的GroupBox中放入一个GroupBox和一个GroupBox。在嵌套的GroupBox中,我放置了3个文本框控件和一个按钮。这是我使用的代码(甚至包括您要查找的递归)

public IEnumerable<Control> GetAll(Control control,Type type)
{
    var controls = control.Controls.Cast<Control>();

    return controls.SelectMany(ctrl => GetAll(ctrl,type))
                              .Concat(controls)
                              .Where(c => c.GetType() == type);
}

To test it in the form load event I wanted a count of all controls inside the initial GroupBox

要在form load事件中测试它,我需要在初始GroupBox中对所有控件进行计数。

private void Form1_Load(object sender, EventArgs e)
{
    var c = GetAll(this,typeof(TextBox));
    MessageBox.Show("Total Controls: " + c.Count());
}

And it returned the proper count each time, so I think this will work perfectly for what you're looking for :)

它每次都返回正确的计数,所以我认为这对你所寻找的是非常有效的:)

#2


28  

In C# (since you tagged it as such) you could use a LINQ expression like this:

在c#中(既然您这样标记它),您可以使用如下的LINQ表达式:

List<Control> c = Controls.OfType<TextBox>().Cast<Control>().ToList();

Edit for recursion:

递归编辑:

In this example, you first create the list of controls and then call a method to populate it. Since the method is recursive, it doesn't return the list, it just updates it.

在本例中,首先创建控件列表,然后调用一个方法来填充它。由于该方法是递归的,所以它不返回列表,而是更新列表。

List<Control> ControlList = new List<Control>();
private void GetAllControls(Control container)
{
    foreach (Control c in container.Controls)
    {
        GetAllControls(c);
        if (c is TextBox) ControlList.Add(c);
    }
}

It may be possible to do this in one LINQ statement using the Descendants function, though I am not as familiar with it. See this page for more information on that.

可能可以在一个LINQ语句中使用子类函数来实现这一点,尽管我对它不是很熟悉。有关这方面的更多信息,请参见此页。

Edit 2 to return a collection:

编辑2以返回一个集合:

As @ProfK suggested, a method that simply returns the desired controls is probably better practice. To illustrate this I have modified the code as follows:

正如@ProfK所建议的,简单地返回所需控件的方法可能是更好的实践。为了说明这一点,我修改了代码如下:

private IEnumerable<Control> GetAllTextBoxControls(Control container)
{
    List<Control> controlList = new List<Control>();
    foreach (Control c in container.Controls)
    {
        controlList.AddRange(GetAllTextBoxControls(c));
        if (c is TextBox)
            controlList.Add(c);
    }
    return controlList;
}

#3


12  

This is an improved version of the recursive GetAllControls() that actually works on private vars:

这是递归GetAllControls()的改进版本,它实际上适用于私有vars:

    private void Test()
    {
         List<Control> allTextboxes = GetAllControls(this);
    }
    private List<Control> GetAllControls(Control container, List<Control> list)
    {
        foreach (Control c in container.Controls)
        {
            if (c is TextBox) list.Add(c);
            if (c.Controls.Count > 0)
                list = GetAllControls(c, list);
        }

        return list;
    }
    private List<Control> GetAllControls(Control container)
    {
        return GetAllControls(container, new List<Control>());
    }

#4


8  

I combined a bunch of the previous ideas into one extension method. The benefits here are that you get the correctly typed enumerable back, plus inheritance is handled correctly by OfType().

我把以前的一些想法组合成一个扩展方法。这里的好处是您可以得到正确类型的可枚举值,并且继承可以由OfType()正确处理。

public static IEnumerable<T> FindAllChildrenByType<T>(this Control control)
{
    IEnumerable<Control> controls = control.Controls.Cast<Control>();
    return controls
        .OfType<T>()
        .Concat<T>(controls.SelectMany<Control, T>(ctrl => FindAllChildrenByType<T>(ctrl)));
}

#5


7  

You can use a LINQ query to do this. This will query everything on the form that is type TextBox

您可以使用LINQ查询来实现这一点。这将查询输入TextBox的窗体上的所有内容

var c = from controls in this.Controls.OfType<TextBox>()
              select controls;

#6


5  

It might be the ancient technique, but it works like charm. I used recursion to change the color of all labels of the control. It works great.

这可能是一种古老的技术,但它就像魅力一样发挥作用。我使用递归来改变控件的所有标签的颜色。它的工作原理。

internal static void changeControlColour(Control f, Color color)
{
    foreach (Control c in f.Controls)
    {

        // MessageBox.Show(c.GetType().ToString());
        if (c.HasChildren)
        {
            changeControlColour(c, color);
        }
        else
            if (c is Label)
            {
                Label lll = (Label)c;
                lll.ForeColor = color;
            }
    }
}

#7


4  

I'd like to amend PsychoCoders answer: as the user wants to get all controls of a certain type we could use generics in the following way:

我想修改一下心理编码员的回答:由于用户想要获得某种类型的所有控件,我们可以用以下方式使用泛型:

    public IEnumerable<T> FindControls<T>(Control control) where T : Control
    {
        // we can't cast here because some controls in here will most likely not be <T>
        var controls = control.Controls.Cast<Control>();

        return controls.SelectMany(ctrl => FindControls<T>(ctrl))
                                  .Concat(controls)
                                  .Where(c => c.GetType() == typeof(T)).Cast<T>();
    }

This way, we can call the function as follows:

这样,我们就可以把函数称为:

private void Form1_Load(object sender, EventArgs e)
{
    var c = FindControls<TextBox>(this);
    MessageBox.Show("Total Controls: " + c.Count());
}

#8


3  

Don't forget that you can also have a TextBox within other controls other than container controls too. You can even add a TextBox to a PictureBox.

不要忘记除了容器控件之外,在其他控件中也可以有一个文本框。你甚至可以在图片框中添加一个文本框。

So you also need to check if

所以你还需要检查一下

someControl.HasChildren = True

in any recursive function.

在任何一个递归函数。

This is the result I had from a layout to test this code:

这是我从布局中得到的测试代码的结果:

TextBox13   Parent = Panel5
TextBox12   Parent = Panel5
TextBox9   Parent = Panel2
TextBox8   Parent = Panel2
TextBox16   Parent = Panel6
TextBox15   Parent = Panel6
TextBox14   Parent = Panel6
TextBox10   Parent = Panel3
TextBox11   Parent = Panel4
TextBox7   Parent = Panel1
TextBox6   Parent = Panel1
TextBox5   Parent = Panel1
TextBox4   Parent = Form1
TextBox3   Parent = Form1
TextBox2   Parent = Form1
TextBox1   Parent = Form1
tbTest   Parent = myPicBox

Try this with one Button and one RichTextBox on a form.

试着在表单上使用一个按钮和一个RichTextBox。

Option Strict On
Option Explicit On
Option Infer Off

Public Class Form1

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

        Dim pb As New PictureBox
        pb.Name = "myPicBox"
        pb.BackColor = Color.Goldenrod
        pb.Size = New Size(100, 100)
        pb.Location = New Point(0, 0)
        Dim tb As New TextBox
        tb.Name = "tbTest"
        pb.Controls.Add(tb)
        Me.Controls.Add(pb)

        Dim textBoxList As New List(Of Control)
        textBoxList = GetAllControls(Of TextBox)(Me)

        Dim sb As New System.Text.StringBuilder
        For index As Integer = 0 To textBoxList.Count - 1
            sb.Append(textBoxList.Item(index).Name & "   Parent = " & textBoxList.Item(index).Parent.Name & System.Environment.NewLine)
        Next

        RichTextBox1.Text = sb.ToString
    End Sub

    Private Function GetAllControls(Of T)(ByVal searchWithin As Control) As List(Of Control)

        Dim returnList As New List(Of Control)

        If searchWithin.HasChildren = True Then
            For Each ctrl As Control In searchWithin.Controls
                If TypeOf ctrl Is T Then
                    returnList.Add(ctrl)
                End If
                returnList.AddRange(GetAllControls(Of T)(ctrl))
            Next
        ElseIf searchWithin.HasChildren = False Then
            For Each ctrl As Control In searchWithin.Controls
                If TypeOf ctrl Is T Then
                    returnList.Add(ctrl)
                End If
                returnList.AddRange(GetAllControls(Of T)(ctrl))
            Next
        End If
        Return returnList
    End Function

End Class

#9


2  

Using reflection:

使用反射:

// Return a list with all the private fields with the same type
List<T> GetAllControlsWithTypeFromControl<T>(Control parentControl)
{
    List<T> retValue = new List<T>();
    System.Reflection.FieldInfo[] fields = parentControl.GetType().GetFields(System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
    foreach (System.Reflection.FieldInfo field in fields)
    {
      if (field.FieldType == typeof(T))
        retValue.Add((T)field.GetValue(parentControl));
    }
}

List<TextBox> ctrls = GetAllControlsWithTypeFromControl<TextBox>(this);

#10


1  

Here is the Solution.

这是解决方案。

https://*.com/a/19224936/1147352

https://*.com/a/19224936/1147352

I have written this piece of code and selected only the panels, you can add more switches or ifs. in it

我已经编写了这段代码并只选择了面板,您可以添加更多的开关或ifs。在这

#11


1  

public List<Control> GetAllChildControls(Control Root, Type FilterType = null)
{
    List<Control> AllChilds = new List<Control>();
    foreach (Control ctl in Root.Controls) {
        if (FilterType != null) {
            if (ctl.GetType == FilterType) {
                AllChilds.Add(ctl);
            }
        } else {
            AllChilds.Add(ctl);
        }
        if (ctl.HasChildren) {
            GetAllChildControls(ctl, FilterType);
        }
    }
    return AllChilds;
}

#12


1  

Here is my extension method for Control, using LINQ, as an adaptation of @PsychoCoder version:

以下是我的控制扩展方法,使用LINQ作为@PsychoCoder版本的改编:

It takes a list of type instead that allows you to not need multiple calls of GetAll to get what you want. I currently use it as an overload version.

它采用了一个类型列表,允许您不需要多次GetAll调用就可以得到您想要的。我目前使用它作为一个重载版本。

public static IEnumerable<Control> GetAll(this Control control, IEnumerable<Type> filteringTypes)
{
    var ctrls = control.Controls.Cast<Control>();

    return ctrls.SelectMany(ctrl => GetAll(ctrl, filteringTypes))
                .Concat(ctrls)
                .Where(ctl => filteringTypes.Any(t => ctl.GetType() == t));
}

Usage:

用法:

//   The types you want to select
var typeToBeSelected = new List<Type>
{
    typeof(TextBox)
    , typeof(MaskedTextBox)
    , typeof(Button)
};

//    Only one call
var allControls = MyControlThatContainsOtherControls.GetAll(typeToBeSelected);

//    Do something with it
foreach(var ctrl in allControls)
{
    ctrl.Enabled = true;
}

#13


1  

   IEnumerable<Control> Ctrls = from Control ctrl in Me.Controls where ctrl is TextBox | ctrl is GroupBox select ctr;

Lambda Expressions

Lambda表达式

IEnumerable<Control> Ctrls = Me.Controls.Cast<Control>().Where(c => c is Button | c is GroupBox);

#14


0  

I modified from @PsychoCoder. All controls could be found now (include nested).

我从@PsychoCoder修改。现在可以找到所有控件(包括嵌套控件)。

public static IEnumerable<T> GetChildrens<T>(Control control)
{
  var type = typeof (T);

  var allControls = GetAllChildrens(control);

  return allControls.Where(c => c.GetType() == type).Cast<T>();
}

private static IEnumerable<Control> GetAllChildrens(Control control)
{
  var controls = control.Controls.Cast<Control>();
  return controls.SelectMany(c => GetAllChildrens(c))
    .Concat(controls);
}

#15


0  

This may work:

这可能工作:

Public Function getControls(Of T)() As List(Of T)
    Dim st As New Stack(Of Control)
    Dim ctl As Control
    Dim li As New List(Of T)

    st.Push(Me)

    While st.Count > 0
        ctl = st.Pop
        For Each c In ctl.Controls
            st.Push(CType(c, Control))
            If c.GetType Is GetType(T) Then
                li.Add(CType(c, T))
            End If
        Next
    End While

    Return li
End Function

I think the function to get all controls you are talking about is only available to WPF.

我认为,您所讨论的所有控件的功能只适用于WPF。

#16


0  

Here is a tested and working generic solution:

这里有一个经过测试的通用解决方案:

I have a large number UpDownNumeric controls, some in the main form, some in groupboxes within the form. I want only the one last selected control to change back-color to green, for which I first set all others to white, using this method: (can also expand to grandchildren)

我有大量的UpDownNumeric控件,有些在主窗体中,有些在窗体的分组框中。我只希望最后选中的控件将背景颜色改为绿色,为此我首先将其他控件设置为白色,使用此方法:(也可以扩展到孙辈)

    public void setAllUpDnBackColorWhite()
    {
        //To set the numericUpDown background color of the selected control to white: 
        //and then the last selected control will change to green.

        foreach (Control cont in this.Controls)
        {
           if (cont.HasChildren)
            {
                foreach (Control contChild in cont.Controls)
                    if (contChild.GetType() == typeof(NumericUpDown))
                        contChild.BackColor = Color.White;
            }
            if (cont.GetType() == typeof(NumericUpDown))
                cont.BackColor = Color.White;
       }
    }   

#17


0  

You can try this if you want :)

如果你想试试这个:

    private void ClearControls(Control.ControlCollection c)
    {
        foreach (Control control in c)
        {
            if (control.HasChildren)
            {
                ClearControls(control.Controls);
            }
            else
            {
                if (control is TextBox)
                {
                    TextBox txt = (TextBox)control;
                    txt.Clear();
                }
                if (control is ComboBox)
                {
                    ComboBox cmb = (ComboBox)control;
                    if (cmb.Items.Count > 0)
                        cmb.SelectedIndex = -1;
                }

                if (control is CheckBox)
                {
                    CheckBox chk = (CheckBox)control;
                    chk.Checked = false;
                }

                if (control is RadioButton)
                {
                    RadioButton rdo = (RadioButton)control;
                    rdo.Checked = false;
                }

                if (control is ListBox)
                {
                    ListBox listBox = (ListBox)control;
                    listBox.ClearSelected();
                }
            }
        }
    }
    private void btnClear_Click(object sender, EventArgs e)
    {
        ClearControls((ControlCollection)this.Controls);
    }

#18


0  

Although several other users have posted adequate solutions, I'd like to post a more general approach that may be more useful.

虽然其他几个用户已经发布了适当的解决方案,但是我希望发布一个更通用的方法,这可能更有用。

This is largely based on JYelton's response.

这主要是基于JYelton的反应。

public static IEnumerable<Control> AllControls(
    this Control control, 
    Func<Control, Boolean> filter = null) 
{
    if (control == null)
        throw new ArgumentNullException("control");
    if (filter == null)
        filter = (c => true);

    var list = new List<Control>();

    foreach (Control c in control.Controls) {
        list.AddRange(AllControls(c, filter));
        if (filter(c))
            list.Add(c);
    }
    return list;
}

#19


0  

    public static IEnumerable<T> GetAllControls<T>(this Control control) where T : Control
    {
        foreach (Control c in control.Controls)
        {
            if (c is T)
                yield return (T)c;
            foreach (T c1 in c.GetAllControls<T>())
                yield return c1;
        }
    }

#20


0  

    public IEnumerable<T> GetAll<T>(Control control) where T : Control
    {
        var type = typeof(T);
        var controls = control.Controls.Cast<Control>().ToArray();
        foreach (var c in controls.SelectMany(GetAll<T>).Concat(controls))
            if (c.GetType() == type) yield return (T)c;
    }

#21


0  

A clean and easy solution (C#):

一个干净简单的解决方案(c#):

static class Utilities {
    public static List<T> GetAllControls<T>(this Control container) where T : Control {
        List<T> controls = new List<T>();
        if (container.Controls.Count > 0) {
            controls.AddRange(container.Controls.OfType<T>());
            foreach (Control c in container.Controls) {
                controls.AddRange(c.GetAllControls<T>());
            }
        }

        return controls;
    }
}

Get all textboxes:

得到所有文本框:

List<TextBox> textboxes = myControl.GetAllControls<TextBox>();

#22


0  

Here is my Extension method. It's very efficient and is lazy.

这是我的扩展方法。它非常高效而且懒惰。

Usage:

用法:

var checkBoxes = tableLayoutPanel1.FindChildControlsOfType<CheckBox>();

foreach (var checkBox in checkBoxes)
{
    checkBox.Checked = false;
}

The code is:

的代码是:

public static IEnumerable<TControl> FindChildControlsOfType<TControl>(this Control control) where TControl : Control
    {
        foreach (var childControl in control.Controls.Cast<Control>())
        {
            if (childControl.GetType() == typeof(TControl))
            {
                yield return (TControl)childControl;
            }
            else
            {
                foreach (var next in FindChildControlsOfType<TControl>(childControl))
                {
                    yield return next;
                }
            }
        }
    }

#23


0  

For anyone looking for a VB version of Adam's C# code written as an extension of the Control class:

对于任何想要寻找一个VB版本的Adam的c#代码,作为控件类的扩展:

''' <summary>Collects child controls of the specified type or base type within the passed control.</summary>
''' <typeparam name="T">The type of child controls to include. Restricted to objects of type Control.</typeparam>
''' <param name="Parent">Required. The parent form control.</param>
''' <returns>An object of type IEnumerable(Of T) containing the control collection.</returns>
''' <remarks>This method recursively calls itself passing child controls as the parent control.</remarks>
<Extension()>
Public Function [GetControls](Of T As Control)(
    ByVal Parent As Control) As IEnumerable(Of T)

    Dim oControls As IEnumerable(Of Control) = Parent.Controls.Cast(Of Control)()
    Return oControls.SelectMany(Function(c) GetControls(Of T)(c)).Concat(oControls.Where(Function(c) c.GetType() Is GetType(T) Or c.GetType().BaseType Is GetType(T))
End Function

NOTE: I've added BaseType matching for any derived custom controls. You can remove this or even make it an optional parameter if you wish.

注意:我已经为任何派生自定义控件添加了BaseType匹配。您可以删除它,甚至可以将它设置为可选参数。

Usage

使用

Dim oButtons As IEnumerable(Of Button) = Me.GetControls(Of Button)()