usuario formulario dinamicamente crear controles control comunes agregar c# .net vb.net winforms controls

c# - formulario - ¿Cómo obtener TODOS los controles secundarios de una forma de Windows Forms de un tipo específico(Button/Textbox)?



controles de windows forms (23)

Necesito obtener todos los controles en un formulario que son de tipo x. Estoy bastante seguro de haber visto ese código una vez en el pasado que usó algo como esto:

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

Sé que puedo repetir todos los controles para que los niños utilicen una función recursiva, pero ¿hay algo más sencillo o más directo, tal vez como el siguiente?

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


Aquí está la Solución.

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

He escrito este fragmento de código y seleccioné solo los paneles, puede agregar más interruptores o ifs. en eso


Aquí está mi método de extensión para Control , usando LINQ, como una adaptación de la versión de @PsychoCoder :

En su lugar, lleva una lista de tipo que le permite no necesitar varias llamadas de GetAll para obtener lo que desea. Actualmente lo uso como una versión de sobrecarga.

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

Uso:

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


Aquí está mi método de extensión. Es muy eficiente y es flojo.

Uso:

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

El código es:

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


Aquí hay otra opción para ti. Lo probé creando una aplicación de muestra, luego puse un GroupBox y un GroupBox dentro del GroupBox inicial. Dentro del GroupBox anidado pongo 3 controles TextBox y un botón. Este es el código que utilicé (incluso incluye la recursión que estabas buscando)

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

Para probarlo en el evento de carga de formulario, quería un recuento de todos los controles dentro del GroupBox inicial

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

Y devolvió el recuento correcto cada vez, así que creo que esto funcionará perfectamente para lo que estás buscando :)


Aquí hay una solución genérica probada y funcional:

Tengo un gran número de controles UpDownNumeric, algunos en el formulario principal, algunos en grupos dentro del formulario. Solo quiero que el último control seleccionado cambie el color de fondo a verde, para lo cual primero configuré todos los demás en blanco, usando este método: (también puede expandirse a los nietos)

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


Aunque otros usuarios han publicado soluciones adecuadas, me gustaría publicar un enfoque más general que pueda ser más útil.

Esto se basa principalmente en la respuesta 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; }


Combiné un montón de las ideas anteriores en un método de extensión. Los beneficios aquí son que obtiene el elemento enumerable correctamente tipeado, además OfType() maneja correctamente la 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))); }


En C # (ya que lo etiquetó como tal) podría usar una expresión LINQ como esta:

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

Editar para la recursión:

En este ejemplo, primero crea la lista de controles y luego llama a un método para poblarlo. Como el método es recursivo, no devuelve la lista, solo la actualiza.

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

Es posible hacer esto en una declaración LINQ utilizando la función Descendants , aunque no estoy tan familiarizado con ella. Vea esta página para más información sobre eso.

Edite 2 para devolver una colección:

Como sugirió @ProfK, un método que simplemente devuelve los controles deseados es probablemente una mejor práctica. Para ilustrar esto, he modificado el código de la siguiente manera:

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


Esta es una versión mejorada de GetAllControls recursivo () que realmente funciona en vars privados:

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


Esto puede funcionar:

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

Creo que la función para obtener todos los controles de los que está hablando solo está disponible para WPF .


Me gustaría enmendar la respuesta de PsychoCoders: como el usuario quiere obtener todos los controles de un cierto tipo, podríamos usar los genéricos de la siguiente manera:

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 esta manera, podemos llamar a la función de la siguiente manera:

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


Modifiqué desde @PsychoCoder. Todos los controles se pueden encontrar ahora (incluir anidados).

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


No olvide que también puede tener un TextBox dentro de otros controles que no sean controles de contenedor. Incluso puede agregar un TextBox a un PictureBox.

Entonces también debe verificar si

someControl.HasChildren = True

en cualquier función recursiva

Este es el resultado que obtuve de un diseño para probar este código:

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

Pruebe esto con un botón y un RichTextBox en un formulario.

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


Para cualquiera que busque una versión VB del código C # de Adam escrito como una extensión de la clase 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

NOTA: He agregado coincidencia de BaseType para cualquier control personalizado derivado. Puede eliminar esto o incluso convertirlo en un parámetro opcional si lo desea.

Uso

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


Puede ser la técnica antigua, pero funciona como el encanto. Usé recursión para cambiar el color de todas las etiquetas del control. Funciona muy 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; } } }


Puede usar una consulta LINQ para hacer esto. Esto consultará todo en el formulario que es tipo TextBox

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


Puedes probar esto si quieres :)

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


Una solución limpia y fácil (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; } }

Obtener todos los cuadros de texto:

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


Usando la reflexión:

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


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


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


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

Expresiones Lambda

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


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