Je dois obtenir tous les contrôles sur un formulaire de type x. Je suis presque sûr d'avoir vu ce code une fois dans le passé qui utilisait quelque chose comme ceci:
dim ctrls() as Control
ctrls = Me.Controls(GetType(TextBox))
Je sais que je peux parcourir tous les contrôles pour que les enfants utilisent une fonction récursive, mais Y at-il quelque chose de plus simple ou plus simple, comme peut-être le suivant?
Dim Ctrls = From ctrl In Me.Controls Where ctrl.GetType Is Textbox
Voici une autre option pour vous. Je l'ai testé en créant un exemple d'application, puis j'ai placé une GroupBox et une GroupBox dans la GroupBox initiale. À l'intérieur de la GroupBox imbriquée, j'ai placé 3 contrôles TextBox et un bouton. C'est le code que j'ai utilisé (même la récursion que vous cherchiez)
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);
}
Pour le tester dans l'événement de chargement de formulaire, je voulais un compte de tous les contrôles à l'intérieur de la GroupBox initiale.
private void Form1_Load(object sender, EventArgs e)
{
var c = GetAll(this,typeof(TextBox));
MessageBox.Show("Total Controls: " + c.Count());
}
Et il a retourné le nombre approprié à chaque fois, donc je pense que cela fonctionnera parfaitement pour ce que vous cherchez :)
En C # (puisque vous l'avez marqué comme tel), vous pouvez utiliser une expression LINQ comme celle-ci:
List<Control> c = Controls.OfType<TextBox>().Cast<Control>().ToList();
Editer pour récursion:
Dans cet exemple, vous créez d'abord la liste de contrôles, puis appelez une méthode pour la renseigner. Comme la méthode est récursive, elle ne renvoie pas la liste, elle la met simplement à jour.
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);
}
}
Cela peut être possible dans une instruction LINQ en utilisant la fonction Descendants
, bien que je ne sois pas aussi familier avec cela. Voir cette page pour plus d'informations à ce sujet.
Edit 2 pour retourner une collection:
Comme @ProfK l'a suggéré, une méthode qui renvoie simplement les contrôles souhaités constitue probablement une meilleure pratique. Pour illustrer cela, j'ai modifié le code comme suit:
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;
}
Ceci est une version améliorée de GetAllControls () récursive qui fonctionne réellement sur les vars privés:
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>());
}
J'ai combiné un tas des idées précédentes dans une méthode d'extension. Les avantages ici sont que vous récupérez l'énumérable correctement typé, plus l'héritage est géré correctement par 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)));
}
Vous pouvez utiliser une requête LINQ pour cela. Cela interrogera tout sur le formulaire qui est de type TextBox
var c = from controls in this.Controls.OfType<TextBox>()
select controls;
C'est peut-être l'ancienne technique, mais cela fonctionne comme un charme. J'ai utilisé la récursivité pour changer la couleur de toutes les étiquettes du contrôle. Cela fonctionne très bien.
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;
}
}
}
J'aimerais modifier la réponse de PsychoCoders: comme l'utilisateur souhaite obtenir tous les contrôles d'un certain type, nous pourrions utiliser les génériques de la manière suivante:
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>();
}
De cette façon, nous pouvons appeler la fonction comme suit:
private void Form1_Load(object sender, EventArgs e)
{
var c = FindControls<TextBox>(this);
MessageBox.Show("Total Controls: " + c.Count());
}
N'oubliez pas que vous pouvez également avoir une zone de texte dans d'autres contrôles autres que les contrôles de conteneur. Vous pouvez même ajouter un TextBox à un PictureBox.
Donc, vous devez également vérifier si
someControl.HasChildren = True
dans toute fonction récursive.
C'est le résultat que j'ai eu d'une mise en page pour tester ce 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
Essayez ceci avecone Buttonet one RichTextBox sur un formulaire.
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
En utilisant la réflexion:
// 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);
Une solution simple et propre (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;
}
}
Obtenir tous les champs de texte:
List<TextBox> textboxes = myControl.GetAllControls<TextBox>();
Vous pouvez utiliser le code ci-dessous
public static class ExtensionMethods
{
public static IEnumerable<T> GetAll<T>(this Control control)
{
var controls = control.Controls.Cast<Control>();
return controls.SelectMany(ctrl => ctrl.GetAll<T>())
.Concat(controls.OfType<T>());
}
}
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;
}
IEnumerable<Control> Ctrls = from Control ctrl in Me.Controls where ctrl is TextBox | ctrl is GroupBox select ctr;
Expressions Lambda
IEnumerable<Control> Ctrls = Me.Controls.Cast<Control>().Where(c => c is Button | c is GroupBox);
Voici la solution.
https://stackoverflow.com/a/19224936/1147352
J'ai écrit ce morceau de code et sélectionné uniquement les panneaux, vous pouvez ajouter plus de commutateurs ou de if. en cela
Voici ma méthode d'extension pour Control
, en utilisant LINQ, comme une adaptation de @PsychoCoder version:
Il faut plutôt une liste de types qui vous permette de ne pas avoir besoin de plusieurs appels de GetAll
pour obtenir ce que vous voulez. Je l'utilise actuellement comme version surchargée.
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;
}
Voici ma méthode d'extension. C'est très efficace et paresseux.
Usage:
var checkBoxes = tableLayoutPanel1.FindChildControlsOfType<CheckBox>();
foreach (var checkBox in checkBoxes)
{
checkBox.Checked = false;
}
Le code est:
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;
}
}
}
}
Voici une solution générique testée et fonctionnelle:
J'ai un grand nombre de contrôles UpDownNumeric, certains dans le formulaire principal, d'autres dans des groupbox dans le formulaire . Je souhaite que seul le dernier contrôle sélectionné change de couleur d'arrière-plan en vert, pour lequel je règle d'abord tous les autres en blanc en utilisant cette méthode: (peut aussi être étendu aux petits-enfants)
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;
}
}
J'ai modifié de @PsychoCoder . Tous les contrôles peuvent être trouvés maintenant (inclure imbriqué).
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);
}
Tu peux essayer ça si tu veux :)
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);
}
Simplement:
For Each ctrl In Me.Controls.OfType(Of Button)()
ctrl.Text = "Hello World!"
Next
Cela peut fonctionner:
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
Je pense que la fonction pour obtenir tous les contrôles dont vous parlez est uniquement disponible pour WPF .
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;
}
Pour ceux qui recherchent une version VB du code C # d'Adam, écrite comme une extension de la classe Control
:
''' <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
REMARQUE: j'ai ajouté la correspondance BaseType
pour tous les contrôles personnalisés dérivés. Vous pouvez le supprimer ou même en faire un paramètre facultatif si vous le souhaitez.
Usage
Dim oButtons As IEnumerable(Of Button) = Me.GetControls(Of Button)()
Bien que plusieurs autres utilisateurs aient publié des solutions adéquates, j'aimerais proposer une approche plus générale qui pourrait être plus utile.
Ceci est largement basé sur la réponse de 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;
}
}