如何获取特定types(button/文本框)的Windows窗体窗体的所有子控件?

我需要获得一个types为x的表单上的所有控件。 我很确定我在过去曾经看到过这样的代码:

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

我知道我可以遍历所有使用recursion函数获取子项的控件,但有没有更容易或更直接的,可能如下所示?

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

这是另一个select。 我通过创build一个示例应用程序来testing它,然后在最初的GroupBox中放置一个GroupBox和一个GroupBox。 在嵌套的GroupBox内部,我放置了3个TextBox控件和一个button。 这是我使用的代码(甚至包括你正在寻找的recursion)

 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); } 

为了在表单加载事件中testing它,我希望计算初始GroupBox中的所有控件

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

而且它每次都返回正确的计数,所以我认为这将适用于你正在寻找的东西:)

在C#中(因为你标记为这样),你可以使用这样的LINQexpression式:

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

编辑recursion:

在这个例子中,你首先创build控件列表,然后调用一个方法来填充它。 由于该方法是recursion的,它不返回列表,它只是更新它。

 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); } } 

在一个使用Descendants函数的LINQ语句中可以这样做,尽pipe我并不熟悉它。 看到这个页面的更多信息。

编辑2返回一个集合:

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

 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; } 

这是一个改进版本的recursionGetAllControls(),实际上在私人variables上工作:

  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>()); } 

我把一堆以前的想法合并成一个扩展方法。 这里的好处是你得到了正确types的枚举,加上inheritance由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))); } 

您可以使用LINQ查询来执行此操作。 这将查询types为TextBox的表单上的所有内容

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

这可能是古老的技术,但它的作品像魅力。 我用recursion来改变控件的所有标签的颜色。 它工作很好。

 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; } } } 

我想修改PsychoCoders答案:因为用户想要获得某种types的所有控件,我们可以按照以下方式使用generics:

  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>(); } 

这样,我们可以调用这个函数如下:

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

不要忘记,您也可以在容器控件以外的其他控件中包含一个TextBox。 你甚至可以添加一个文本框到一个PictureBox。

所以你还需要检查是否

 someControl.HasChildren = True 

在任何recursion函数中。

这是我从布局testing这个代码的结果:

 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 

尝试一个表单上的一个button一个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 

使用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); 

这是解决scheme。

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

我已经写了这段代码,只select面板,你可以添加更多的开关或ifs。 在里面

 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; } 

这里是我的Control扩展方法,使用LINQ,作为@PsychoCoder版本的改编:

它需要一个types的列表,而不需要多次调用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)); } 

用法:

 // 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; } 
  IEnumerable<Control> Ctrls = from Control ctrl in Me.Controls where ctrl is TextBox | ctrl is GroupBox select ctr; 

Lambdaexpression式

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

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

 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); } 

这可能工作:

 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 

我认为获取所有控件的函数只能用于WPF 。

这是一个经过testing和工作的通用解决scheme

我有大量的UpDownNumeric控件,一些在主窗体中,一些在groupboxes窗体中。 我只想要最后一个选定的控件将背景颜色变成绿色,为此我首先使用这种方法将所有其他颜色设置为白色(也可以展开给孙子们)

  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; } } 

你可以试试这个,如果你想:)

  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); } 

虽然其他几个用户已经发布了适当的解决scheme,但是我想发布一个更加通用的方法,可能会更有用。

这主要基于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; } 
  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; } } 
  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; } 

清洁和简单的解决scheme(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; } } 

获取所有文本框:

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

这是我的扩展方法。 这是非常有效的,是懒惰的。

用法:

 var checkBoxes = tableLayoutPanel1.FindChildControlsOfType<CheckBox>(); foreach (var checkBox in checkBoxes) { checkBox.Checked = false; } 

代码是:

 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; } } } }