Crear (y usar) arrays de controles en .NETPublicado el 14/Nov/2002
|
Introducción:
En las versiones clásicas de Visual Basic, podíamos crear arrays de controles, lo cual nos permitía acceder a esos controles de la forma habitual de los arrays: Text1(0).Text = "lo que sea".
Pero en .NET Framework, (no sólo en VB.NET), no existe esa posibilidad. Bueno, casi, ya que si conviertes el código de tu aplicación de VB6 a VB.NET, el asistente te creará un array de controles, pero...Puede que este código que te muestro no sea el "mejor" para simular los arrays de controles, pero si le "pillas" (por no decir coges), el tranquillo, la verdad es que resulta fácil de usar y, lo más importante, de implementar.
Ya que sólo tienes que hacer un par de cosillas para que todo esto esté disponible, con la ventaja de que si añades nuevos controles, prácticamente no tienes que hacer nada... salvo lo que en principio hagas para manejar esos arrays... me explico, si has convertido el código desde VB6 ya tendrás creado el código, pero si añades nuevos controles, te tienes que "preocupar" de que esos nuevos controles formen parte del array.
Con el código que te propongo no tienes que preocuparte de nada... salvo crear las referencias a la clase que contendrá los controles e inicializarlas...
Bueno, también tendrás que añadir o crear los eventos que manejarán esos controles... siempre y cuando quieras que todo sea "automático", ya que también puedes hacerlo por las "bravas", (es decir, interceptar por separado los eventos de cada control), en cuyo caso no tiene sentido usar el código que te propongo...Te resumo brevemente los "requisitos" para poder usar esto de los arrays de controles:
1- Tienes que añadir al proyecto el fichero que contiene la declaración de la clase ControlArray
2- Los controles que quieras que estén en el array (un array para cada tipo de control o grupo de controles relacionados) deberán tener el mismo nombre y deberán acabar con el signo de subrayado bajo seguido de un número que actuará de índice. Por tanto es recomendable para que la cosa funcione bien, de que esos valores sean consecutivos y que empiecen por cero (lee la nota).
3- Hacer una llamada al método AsignarControles (desde el Form_Load)
4- Asignar los eventos que interceptarán (esto sólo es necesario si quieres que un mismo evento sea válido para todos los controles del array)Nota del 09/Abr/07:
Los índices a usar en los controles deben empezar por cero, no solo porque los arrays en .NET empiezan por cero y así el uso es más lógico, sino también porque esta clase la creé pensando en los que usábamos arrays de controles de Visual Basic 6.0 (o anterior) y cuando creábamos un array de controles, el primero de la lista era el que tenía el índice cero.
Por tanto, si vas a crear un array de 3 controles TextBox, cuyo nombre será TextBox1, los controles a añadir a ese array deben llamarse: TextBox1_0, TextBox1_1 y TextBox1_2. De esa forma podrás acceder con un bucle desde 0 hasta 1 menos del número de elementos del array y otras cosas que normalmente harás con los arrays.
Espero que esta nota, aunque llegue con varios años de retraso, sirva para los que leen este artículo por primera vez.En cuanto veas el ejemplo, te darás cuenta que no es tan complicado.
Aquí te muestro las ventajas de asignar los eventos y manipularlos desde un mismo procedimiento, en este caso, cuando el control recibe el foco, selecciona todo el texto y cambia el color de la etiqueta que tiene el mismo índice:
Private Sub TextBox1_Enter(ByVal sender As Object, ByVal e As System.EventArgs) Dim txt As TextBox = CType(sender, TextBox) Dim Index As Integer = m_TextBox1.Index(txt) ' txt.SelectAll() ' resaltar la etiqueta m_Label1(Index).BackColor = Color.FromKnownColor(KnownColor.ControlDark) End SubEn el formulario de ejemplo, se procesan estos eventos:
TextBox.KeyPress, cuando se pulsa Intro se pasa al siguiente control del array, si es el último, se pasa el foco al primer Option.
TextBox.Enter, (cuando tiene el foco), se selecciona todo el texto y se resalta la etiqueta con el mismo índice.
TextBox.Leave, (cuando pierde el foco), la etiqueta con el mismo índice se deja con el color predeterminado.
RadioButton.KeyPress, al pulsar Intro se pasa al siguiente Option y si es el último, se pasa al primer TextBox.
Espero que te sea de utilidad.
Nos vemos.
Guillermo
Aquí tienes el código tanto para VB como para C#: ArrayControles.zip 17.6 KB
Crear array de controles con Visual Basic .NET
Aquí tienes el código de la clase ControlArray, así como el código del formulario en el que implementar esto de los arrays de controles.
'------------------------------------------------------------------------------ ' ControlArray (09/Ago/02) ' Clase para simular un array de controles ' ' ©Guillermo 'guille' Som, 2002 '------------------------------------------------------------------------------ Option Strict On '<summary> ' Colección de objetos de tipo Control '</summary> Public Class ControlArray Inherits CollectionBase ' Private mNombre As String ' Public Sub New() MyBase.New() End Sub Public Sub New(ByVal elNombre As String) MyBase.New() mNombre = elNombre End Sub ' Public Function Add(ByVal ctrl As Control) As Integer Return MyBase.List.Add(ctrl) End Function ' ' Asignar los controles que contendrá esta colección (14/Nov/02) Public Sub AsignarControles(ByVal ctrls As Control.ControlCollection, _ Optional ByVal elNombre As String = "") ' Asignar los controles a los arrays, ' para que esto funcione automáticamente los nombres de los controles ' deberían tener el formato: nombre_numero ' nombre del control seguido de un guión bajo y el índice If elNombre = "" Then elNombre = mNombre End If ' si no se indica el nombre de los controles a añadir, ' lanzar una excepción If elNombre = "" Then Throw New ArgumentException( _ "No se ha indicado el nombre base de los controles") Exit Sub End If ' Me.Clear() asignarLosControles(ctrls, elNombre) Me.Reorganizar() End Sub Private Sub asignarLosControles( _ ByVal ctrls As Control.ControlCollection, _ ByVal elNombre As String) Dim ctr As Control ' For Each ctr In ctrls ' Hacer una llamada recursiva por si este control "contiene" otros asignarLosControles(ctr.Controls, elNombre) ' If ctr.Name.IndexOf(elNombre) > -1 Then Me.Add(ctr) End If Next End Sub ' Public Function Contains(ByVal ctrl As Control) As Boolean list.Contains(ctrl) End Function ' Public Function IndexOf(ByVal ctrl As Control) As Integer Return list.IndexOf(ctrl) End Function ' Public Function Index(ByVal name As String) As Integer Dim ctrl As Control Dim i As Integer Dim hallado As Integer = -1 ' For i = 0 To List.Count - 1 ctrl = CType(list(i), Control) If StrComp(ctrl.Name, name, CompareMethod.Text) = 0 Then hallado = i Exit For End If Next Return hallado End Function Public Function Index(ByVal ctrl As Control) As Integer Dim i As Integer ' i = ctrl.Name.LastIndexOf("_") ' Si el nombre no tiene el signo _ If i = -1 Then i = list.IndexOf(ctrl) Else i = CInt(ctrl.Name.Substring(i + 1)) End If Return i End Function ' Public Sub Insert(ByVal index As Integer, ByVal ctrl As Control) List.Insert(index, ctrl) End Sub ' Default Public Property Item(ByVal index As Integer) As Control Get Return CType(List.Item(index), Control) End Get Set(ByVal Value As Control) list.Item(index) = Value End Set End Property Default Public Property Item(ByVal name As String) As Control Get Dim index As Integer = Me.Index(name) ' Si existe, devolverlo, sino, crear uno nuevo If index = -1 Then 'index = Me.Add(ctrl) End If Return CType(List.Item(index), Control) End Get Set(ByVal Value As Control) Dim index As Integer = Me.Index(name) If index = -1 Then index = Me.Add(Value) End If list.Item(index) = Value End Set End Property Default Public Property Item(ByVal ctrl As Control) As Control Get Return CType(List(Me.IndexOf(ctrl)), Control) End Get Set(ByVal Value As Control) List(Me.IndexOf(ctrl)) = Value End Set End Property ' Public Property Nombre() As String Get Return mNombre End Get Set(ByVal Value As String) mNombre = Value End Set End Property ' Public Sub Remove(ByVal ctrl As Control) List.Remove(ctrl) End Sub ' ' Reorganizar el contenido de la colección y ordenar por índice Public Sub Reorganizar() Dim ca As New ControlArray() Dim ctr As Control Dim i As Integer ' For i = 0 To Me.Count - 1 For Each ctr In Me If i = Me.Index(ctr) Then ca.Add(ctr) Exit For End If Next Next ' Me.Clear() For Each ctr In ca Me.Add(ctr) Next End Sub End Class
'------------------------------------------------------------------------------ ' Prueba para usar la clase ControlArray con VB .NET (14/Nov/02) ' ' ©Guillermo 'guille' Som, 2002 '------------------------------------------------------------------------------ Option Strict On Public Class Form1 Inherits System.Windows.Forms.Form #Region " Código generado por el Diseñador de Windows Forms " '... #End Region ' ' Arrays para contener los controles ' (definir los arrays que vamos a usar) Private m_Label1 As New ControlArray("Label1") Private m_TextBox1 As New ControlArray("TextBox1") Private m_RadioButton1 As New ControlArray("RadioButton1") ' ' Asignar los eventos a los controles Private Sub asignarEventos() Dim txt As TextBox Dim opt As RadioButton ' ' Aquí estarán los procedimientos a asignar a cada array de controles ' For Each opt In m_RadioButton1 AddHandler opt.KeyPress, AddressOf RadioButton1_KeyPress Next For Each txt In m_TextBox1 AddHandler txt.Enter, AddressOf TextBox1_Enter AddHandler txt.KeyPress, AddressOf TextBox1_KeyPress AddHandler txt.Leave, AddressOf TextBox1_Leave Next ' End Sub ' Private Sub Form1_Load(ByVal sender As Object, _ ByVal e As System.EventArgs) Handles MyBase.Load ' ' Asignar los controles y reorganizar los índices m_Label1.AsignarControles(Me.Controls) m_TextBox1.AsignarControles(Me.Controls) m_RadioButton1.AsignarControles(Me.Controls) ' Asignar sólo los eventos asignarEventos() End Sub ' Private Sub TextBox1_Enter(ByVal sender As Object, _ ByVal e As System.EventArgs) ' Dim txt As TextBox = CType(sender, TextBox) Dim Index As Integer = m_TextBox1.Index(txt) ' txt.SelectAll() ' resaltar la etiqueta m_Label1(Index).BackColor = Color.FromKnownColor(KnownColor.ControlDark) ' End Sub Private Sub TextBox1_Leave(ByVal sender As Object, ByVal e As EventArgs) ' Dim txt As TextBox = CType(sender, TextBox) Dim Index As Integer = m_TextBox1.Index(txt) ' ' poner la etiqueta con el color normal m_Label1(Index).BackColor = Color.FromKnownColor(KnownColor.Control) End Sub Private Sub TextBox1_KeyPress(ByVal sender As Object, _ ByVal e As System.Windows.Forms.KeyPressEventArgs) ' If e.KeyChar = ChrW(Keys.Return) Then Dim txt As TextBox = CType(sender, TextBox) Dim Index As Integer = m_TextBox1.Index(txt) ' If Index = 2 Then m_RadioButton1(0).Focus() Else m_TextBox1(Index + 1).Focus() End If End If End Sub ' Private Sub RadioButton1_KeyPress(ByVal sender As Object, _ ByVal e As System.Windows.Forms.KeyPressEventArgs) If e.KeyChar = ChrW(Keys.Return) Then Dim opt As RadioButton = CType(sender, RadioButton) Dim Index As Integer = m_RadioButton1.Index(opt) ' If Index = 0 Then m_RadioButton1(Index + 1).Focus() Else m_TextBox1(0).Focus() End If End If End Sub ' Private Sub btnCerrar_Click(ByVal sender As Object, _ ByVal e As System.EventArgs) _ Handles btnCerrar.Click Me.Close() End Sub End Class
Nota del 09/Abr/07:
En el código original, el texto resaltado estaba mal, ya que era m_TextBox1, cuando debe ser m_RadioButton1.
Crear array de controles con C#
Aquí tienes el código de la clase ControlArray, así como el código del formulario en el que implementar esto de los arrays de controles.
//----------------------------------------------------------------------------- // ControlArray (14/Nov/02) // Clase para simular un array de controles // // Versión para C# // // ©Guillermo 'guille' Som, 2002 //----------------------------------------------------------------------------- using System; using System.Collections; using System.Windows.Forms; //// Colección de objetos de tipo Control // namespace ArrayControlesCS { public class ControlArray : CollectionBase { // private string mNombre; // public ControlArray() { } public ControlArray(string elNombre){ mNombre = elNombre; } // public int Add(Control ctrl) { return base.List.Add(ctrl); } // // Asignar los controles que contendrá esta colección (14/Nov/02) public void AsignarControles(Control.ControlCollection ctrls) { string elNombre = mNombre; this.AsignarControles(ctrls, elNombre); } public void AsignarControles( Control.ControlCollection ctrls, string elNombre) { // Asignar los controles a los arrays, // para que esto funcione automáticamente los nombres de los controles // deberían tener el formato: nombre_numero // nombre del control seguido de un guión bajo y el índice if( elNombre == null ) elNombre = mNombre; // si no se indica el nombre de los controles a añadir, // lanzar una excepción if( elNombre == "" ) throw new ArgumentException( "No se ha indicado el nombre base de los controles"); // this.Clear(); asignarLosControles(ctrls, elNombre); this.Reorganizar(); } private void asignarLosControles( Control.ControlCollection ctrls, string elNombre) { foreach(Control ctr in ctrls){ // Hacer una llamada recursiva por si este control "contiene" otros asignarLosControles(ctr.Controls, elNombre); // if( ctr.Name.IndexOf(elNombre) > -1 ) this.Add(ctr); } } // public bool Contains(Control ctrl) { return base.List.Contains(ctrl); } public int IndexOf(Control ctrl) { return base.List.IndexOf(ctrl); } public int Index(string name) { Control ctrl; int hallado = -1; // for(int i=0; i<= List.Count - 1; i++){ ctrl = (Control)base.List[i]; if( ctrl.Name == name ){ hallado = i; break; } } return hallado; } public int Index(Control ctrl) { int i; // i = ctrl.Name.LastIndexOf("_"); // Si el nombre no tiene el signo if( i == -1 ){ i = base.List.IndexOf(ctrl); }else{ i = Convert.ToInt32(ctrl.Name.Substring(i + 1)); } return i; } // void Insert(int index, Control ctrl) { List.Insert(index, ctrl); } // public Control this[int index] { get{ return ((Control)List[index]); } set{ base.List[index] = value; } } public Control this[string name] { get{ int index = this.Index(name); return ((Control)List[index]); } set{ int index = this.Index(name); if( index == -1 ){ index = this.Add(value); } base.List[index] = value; } } public Control this[Control ctrl] { get{ return (Control)List[this.IndexOf(ctrl)]; } set{ List[this.IndexOf(ctrl)] = value; } } // public string Nombre { get{ return mNombre; } set{ mNombre = value; } } // void Remove(Control ctrl) { List.Remove(ctrl); } // // Reorganizar el contenido de la colección y ordenar por índice public void Reorganizar() { ControlArray ca = new ControlArray(); // for(int i=0; i<= this.Count - 1; i++){ foreach(Control ctr in this){ if( i == this.Index(ctr) ){ ca.Add(ctr); break; } } } // this.Clear(); foreach(Control ctr in ca){ this.Add(ctr); } } } } /* '------------------------------------------------------------------------------ ' Prueba para usar la clase ControlArray con C# (14/Nov/02) ' ' ©Guillermo 'guille' Som, 2002 '------------------------------------------------------------------------------ */ using System; using System.Drawing; using System.Collections; using System.ComponentModel; using System.Windows.Forms; using System.Data; namespace ArrayControlesCS { ////// Descripción breve de Form1. /// public class Form1 : System.Windows.Forms.Form { //... #region Windows Form Designer generated code //... #endregion //... // Arrays para contener los controles // (definir los arrays que vamos a usar) ControlArray m_Label1 = new ControlArray("Label1"); ControlArray m_TextBox1 = new ControlArray("TextBox1"); ControlArray m_RadioButton1 = new ControlArray("RadioButton1"); // // Asignar los eventos a los controles private void asignarEventos() { // // Aquí estarán los procedimientos a asignar a cada array de controles // foreach(RadioButton opt in m_RadioButton1) { opt.KeyPress += new KeyPressEventHandler(RadioButton1_KeyPress); } foreach(TextBox txt in m_TextBox1) { txt.Enter += new System.EventHandler(TextBox1_Enter); txt.KeyPress += new KeyPressEventHandler(TextBox1_KeyPress); txt.Leave += new System.EventHandler(TextBox1_Leave); } } private void btnCerrar_Click(object sender, System.EventArgs e) { this.Close(); } private void Form1_Load(object sender, System.EventArgs e) { // Asignar los controles y reorganizar los índices m_Label1.AsignarControles(this.Controls); m_TextBox1.AsignarControles(this.Controls); m_RadioButton1.AsignarControles(this.Controls); // Asignar sólo los eventos asignarEventos(); } void TextBox1_Enter(object sender, System.EventArgs e ) { // TextBox txt = ((TextBox)sender); int Index = m_TextBox1.Index(txt); // txt.SelectAll(); // resaltar la etiqueta m_Label1[Index].BackColor = Color.FromKnownColor(KnownColor.ControlDark); // } void TextBox1_Leave(object sender, System.EventArgs e ) { // TextBox txt = ((TextBox)sender); int Index = m_TextBox1.Index(txt); // // poner la etiqueta con el color normal m_Label1[Index].BackColor = Color.FromKnownColor(KnownColor.Control); } void TextBox1_KeyPress(object sender, KeyPressEventArgs e ) { // if( e.KeyChar == '\r' ) { TextBox txt = ((TextBox)sender); int Index = m_TextBox1.Index(txt); // if( Index == 2 ) { m_RadioButton1[0].Focus(); } else { m_TextBox1[Index + 1].Focus(); } } } void RadioButton1_KeyPress(object sender, KeyPressEventArgs e ) { if( e.KeyChar == '\r' ) { RadioButton opt = ((RadioButton)sender); int Index = m_RadioButton1.Index(opt); // if( Index == 0 ) { m_RadioButton1[Index + 1].Focus(); } else { m_TextBox1[0].Focus(); } } } } } Nota del 09/Abr/07:
En el código original, el texto resaltado estaba mal, ya que era m_TextBox1, cuando debe ser m_RadioButton1.