none
Recorrer colección de controles existentes en un formulario RRS feed

  • Pregunta

  • De antemano quiero agradecer por tu oportuna ayuda, quisiera saber si me puedes ayudar con lo siguiente: tengo unos textbox,un groupbox al cual se le agregan textbox dinamicamente llamados "demandas", y un boton de nombre "Calcular" que realiza calculos matematicos,antes que realice los calculos valide que todos los cambos han sido diligenciados y mediante el siguiente codigo: 

            Dim Ctl As Control
            Dim Txt As Control
            Dim x As Integer
            For x = Me.Controls.Count - 1 To 0 Step -1
                Ctl = Me.Controls.Item(x)
                If TypeOf (Ctl) Is TextBox Then
                    Dim Control As TextBox = Ctl
                    If Control.Tag = 1 Then
                        If Control.Text.Trim = "" Then
                            MsgBox("Debe de establecer el valor del " & Control.AccessibleName)
                            Control.BackColor = Color.Yellow
                            Control.Focus()
                            ValidaDatos = False
                            Exit Function
                        Else
                            Control.BackColor = Color.White
                        End If
                    End If
                End If
            Next

    Pero solo me valida los textbox que estan por fuera del groupbox, quisiera saber si me puedes ayuda haciendo que tambien me valide los textbox demandas que estan dentro del groupbox

    Sin otro particular agradeciendo tu oportuna ayuda.

    domingo, 27 de mayo de 2012 5:03

Respuestas

  • "John Paz" escribió:

    > antes que realice los calculos valide que todos los cambos han sido
    > diligenciados y mediante el siguiente codigo:
    >
    > For x = Me.Controls.Count - 1 To 0 Step -1
    >
    > Next
    >
    > Pero solo me valida los textbox que estan por fuera del groupbox,
    > quisiera saber si me puedes ayuda haciendo que tambien me valide
    > los textbox demandas que estan dentro del groupbox

    Hola, John:

    Si la palabra clave Me hace referencia al formulario donde tienes insertados tanto los controles TextBox como GroupBox, al recorrer el siguiente bucle:

      For x = Me.Controls.Count - 1 To 0 Step -1

    Únicamente obtendrás los controles que tienen como contenedor al formulario, que es lo que te está sucediendo. Para obtener los CONTROLES EXISTENTES ÚNICAMENTE EN EL CONTROL GROUPBOX, tendrías que recorrer su colección de controles:

            For Each ctrl As Control In GroupBox1.Controls


            Next

    Pero si deseas obtener todos los controles TextBox, con independencia que su contenedor sea un formulario, un control GroupBox o cualquier otro objeto contenedor, tienes que implementar una función que se llame a sí misma (de manera recursiva), para recorrer su posible colección Controls.

    Por ejemplo, podrías hacer uso de la siguiente función:

        ''' <summary>
        ''' Obtiene una colección con los controles de un determinado
        ''' tipo existentes en un contenedor superior.
        ''' </summary>
        ''' <typeparam name="T">Tipo de control que se desea obtener.</typeparam>
        ''' <param name="parentContainer">Objeto Control que actua de
        ''' contenedor para el tipo de control que se desea obtener.</param>
        ''' <param name="includeInheritedControls">Indica si se incluyen en la
        ''' colección aquellos controles que heredan de la clase especificada.</param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Function GetTypeControls(Of T As Control)( _
            parentContainer As Control, includeInheritedControls As Boolean) As List(Of T)
    
            If (parentContainer Is Nothing) Then Return Nothing
    
            Dim controls As New List(Of T)
    
            ' System.Type para el tipo de dato especificado.
            '
            Dim typeT As Type = GetType(T)
    
            For Each ctrl As Control In parentContainer.Controls
    
                If (includeInheritedControls) Then
                    If (TypeOf ctrl Is T) Then _
                        controls.Add(DirectCast(ctrl, T))
    
                Else
                    ' System.Type del control.
                    '
                    Dim typeControl As Type = ctrl.GetType()
                    If (typeControl.Equals(typeT)) Then _
                        controls.Add(DirectCast(ctrl, T))
    
                End If
    
                controls.AddRange(Me.GetTypeControls(Of T)(ctrl, includeInheritedControls))
    
            Next
    
            Return controls
    
        End Function

    Este método se encuentra basado en el siguiente ejemplo del compañero Lluís Franco:

    How to: Obtener controles de un formulario con generics

    Pero con la salvedad que el suyo utiliza el operador 'is' del lenguaje C# (que equivale al operador TypeOf de Visual Basic .net), con lo que se devolverán los controles de la clase especificada (TextBox en éste caso), más aquellos que hereden de la misma (aquellos que hereden de TextBox).

    Y como puede ocurrir que me interese obtener sólo los controles de un determinado tipo, no los que deriven de él, mi código obtiene el valor System.Type para igualar los controles existentes en la colección. No obstante, la función toma un segundo parámetro (includeInheritedControls) por si queremos incluir en la búsqueda aquellos controles que puedan heredar de la clase especificada.

    Dicho ésto, cuando desees recuperar todos los controles TextBox, ejecutarías lo siguiente:

            ' Obtenemos todos los controles TextBox que se encuentren
            ' tanto en el formulario como en cualquier otro control
            ' contenedor existente en el formulario actual.
            '
            Dim ctrls As List(Of TextBox) = Me.GetTypeControls(Of TextBox)(Me, False)
    
            For Each ctrl As Control In ctrls
    
                If (Not (TypeOf ctrl Is TextBox)) Then
                    ' Si el control no es del tipo TextBox,
                    ' continuamos el bucle.
                    '
                    Continue For
                End If
    
                ' El control es del tipo TextBox.
                '
                Dim tb As TextBox = DirectCast(ctrl, TextBox)
    
                ' Si el valor de la propiedad Tag es distinto 
                ' de 1, continuamos el bucle.
                '
                If (CInt(tb.Tag) <> 1) Then Continue For
    
                ' Verificamos si tiene algo escrito.
                '
                If (tb.Text.Trim() = String.Empty) Then
                    MessageBox.Show("Debe de establecer el valor del " & tb.AccessibleName)
                    tb.BackColor = Color.Yellow
                    tb.Focus()
                    ValidaDatos = False
                    Return
                End If
    
                ' Hay algo escrito en el contro.
                '
                tb.BackColor = Color.White
    
            Next

    Me imagino que estarás utilizando la versión 2.0 o superior del marco de trabajo de .NET (Visual Basic 2005 o superior), porque de no ser así, no vas a poder utilizar listas genéricas. ;-)

    Un saludo


    Enrique Martínez
      [MS MVP - VB]

    Nota informativa: La información contenida en este mensaje, así como el código fuente incluido en el mismo, se proporciona «COMO ESTÁ», sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, activa la instrucción Option Strict.


    domingo, 27 de mayo de 2012 7:54
    Moderador
  • Tenías que haber especificado el código que ejecutas para crear los controles TextBox de manera dinámica.

    Inicia un nuevo proyecto y en el formulario de inicio inserta dos controles Button y un control GroupBox. Añade al mismo el código de la función GetTypeControls que te indiqué en un mensaje anterior, y en el evento Click del primer control Button, inserta el siguiente código:

        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button4.Click
    
            ' Creamos tres controles TextBox
            '
            For index As Integer = 1 To 3
    
                Dim tb As New TextBox()
    
                ' Establecemos el nombre del control
                '
                tb.Name = String.Format("Demanda{0}", index)
    
                ' Le asignamos un valor a la propiedad Tag.
                '
                tb.Tag = 1
    
                ' A su propiedad AccessibleName le asignamos
                ' el nombre del control.
                '
                tb.AccessibleName = tb.Name
    
                ' Indicamos la posición del control.
                '
                tb.Location = New Point(3, 25 * index)
    
                ' Lo añadimos a su contenedor, en éste caso
                ' a un control GroupBox.
                '
                tb.Parent = GroupBox1
    
            Next
    
        End Sub

    Al crear los controles dinámicamente, no queda más remedio que configurar el valor de sus propiedades en tiempo de ejecución. En éste ejemplo le estoy asignando a la propiedad AccessibleName el mismo valor que tiene la propiedad Name, porque no sé qué valor asignarle. Pero creo que es suficiente para mostrar cómo lo tienes que hacer.

    Ahora, en el evento Click del segundo control Button, inserta el código para comprobar si se ha escrito algo en los controles TextBox:

        Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
    
            ' Obtenemos todos los controles TextBox que se encuentren
            ' tanto en el formulario como en cualquier otro control
            ' contenedor existente en el formulario actual.
            '
            Dim ctrls As List(Of TextBox) = GetTypeControls(Of TextBox)(Me, False)
    
            For Each ctrl As Control In ctrls
    
                If (Not (TypeOf ctrl Is TextBox)) Then
                    ' Si el control no es del tipo TextBox,
                    ' continuamos el bucle.
                    '
                    Continue For
                End If
    
                ' El control es del tipo TextBox.
                '
                Dim tb As TextBox = DirectCast(ctrl, TextBox)
    
                ' Si el valor de la propiedad Tag es distinto 
                ' de 1, continuamos el bucle.
                '
                If (CInt(tb.Tag) <> 1) Then Continue For
    
                ' Verificamos si tiene algo escrito.
                '
                If (tb.Text.Trim() = String.Empty) Then
                    MessageBox.Show("Debe de establecer el valor del " & tb.AccessibleName)
                    tb.BackColor = Color.Yellow
                    tb.Focus()
                    ValidaDatos = False
                    Return
                End If
    
                ' Hay algo escrito en el contro.
                '
                tb.BackColor = Color.White
    
            Next
    
        End Sub

    Como podrás ver, es el mismo código que te indiqué en mi primera respuesta. Cuando pulses el segundo control Button (aquel al que parece ser tu le llamas CALCULAR), aparecerá en amarillo el color de fondo de aquellos controles TextBox donde no se haya escrito nada.


    Enrique Martínez
      [MS MVP - VB]

    Nota informativa: La información contenida en este mensaje, así como el código fuente incluido en el mismo, se proporciona «COMO ESTÁ», sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, activa la instrucción Option Strict.



    martes, 29 de mayo de 2012 15:17
    Moderador
  • "Pedro Ávila (MAP)" preguntó:

    > Hola @Enrique
    >
    > Si tuvieras en un contenedor groupBox dos comboBox como los
    > identificarias para que en su propiedad datasource pasarle
    > una lista de datos.
    >
    > Pero imaginando que esos controles ComboBox se crearon en
    > tiempo de ejecución.

    Pedro, en Visual Basic .NET, C#, y me imagino que igual sucederá en cualquier otro lenguaje .NET, todos los controles se crean en tiempo de ejecución, porque cuando arrastramos un control al formulario en tiempo de diseño, lo que hace el IDE de Visual Studio es escribir el código necesario en el procedimiento InitializeComponent del formulario para que ese control se cree correctamente en tiempo de ejecución. ¿Que no deseas arrastrar el control al formulario en tiempo de diseño? Me parece estupendo, pero tendrás que hacer lo mismo que hace el IDE para identificar un control, que es establecer el valor oportuno a su propiedad Name, de igual manera que identificamos a una persona cualquiera por su nombre, porque de no hacerlo de esa manera, ¿cómo pretendes identificar un control, sea ComboBox o TextBox?

    También podrías establecerle un valor adecuado a la propiedad Tag para identificar al control ComboBox. Pero si te es suficiente con el valor de la propiedad Name, ¿para qué asignar un valor Object a la propiedad Tag que posteriormente tendrás que convertir al tipo de dato correcto?

    La diferencia está en que mientras que creamos el control en tiempo de diseño, disponemos de una variable objeto que es reconocida por el IDE, y por tanto, por la característa intellisense de Visual Studio, no así cuando creamos el control en tiempo de ejecución, ya que aquí intellisense nos va a servir de bien poco. ;-)

    El siguiente ejemplo crea en tiempo de ejecución un control GroupBox y dos controles ComboBox. Asimismo se configura la propiedad DataSource de ambos controles, y le añade el controlador para el evento SelectedIndexChanged de los mismos:

        Private Sub Button5_Click(sender As Object, e As EventArgs) Handles Button5.Click
    
            ' Creamos y configuramos un control GroupBox.
            '
            Dim gb As New GroupBox()
    
            gb.Name = "MyGroupBox1" ' Le asignamos su nombre.
            gb.Location = New Point(20, 50)
            gb.Size = New Size(500, 200)
    
            ' Creamos y configuramos un nuevo control ComboBox.
            '
            Dim cb As ComboBox = CreateComboBox("MyComboBox1", New Point(30, 30), New Size(200, 25))
    
            ' Configuramos el enlace a datos.
            '
            Dim cmd As New SqlCommand()
            cmd.CommandText = "SELECT IdFactura, IdCliente FROM Facturas"
    
            cb.DataSource = GetData(cmd)
            cb.DisplayMember = "IdFactura"
            cb.ValueMember = "IdCliente"
    
            ' Lo añadimos al control GroupBox creado anteriormente.
            '
            cb.Parent = gb
    
            ' Configuramos un segundo control ComboBox.
            '
            cb = CreateComboBox("MyComboBox2", New Point(250, 30), New Size(200, 25))
    
            ' Configuramos el enlace a datos.
            '
            cmd = New SqlCommand()
            cmd.CommandText = "SELECT IdCliente, Nombre FROM Clientes"
    
            cb.DataSource = GetData(cmd)
            cb.DisplayMember = "Nombre"
            cb.ValueMember = "IdCliente"
    
            ' Lo añadimos al control GroupBox creado anteriormente.
            '
            cb.Parent = gb
    
            ' Por último, añadimos el control GroupBox al formulario.
            '
            gb.Parent = Me
    
        End Sub
    
        Private Function CreateComboBox(name As String, location As Point, size As Size) As ComboBox
    
            Dim cb As New ComboBox()
            cb.Name = name
            cb.Location = location
            cb.Size = size
    
            ' Establecemos el controlador para su evento SelectedIndexChanged.
            '
            AddHandler cb.SelectedIndexChanged, AddressOf ComboBoxOnSelectedIndexChanged
    
            Return cb
    
        End Function
    
        Private Sub ComboBoxOnSelectedIndexChanged(sender As Object, e As EventArgs)
    
            ' Obtenemos la referencia al control ComboBox
            ' que ha desencadenado el evento.
            '
            Dim cb As ComboBox = DirectCast(sender, ComboBox)
    
            ' Obtenemos el valor de su propiedad SelectedValue
            '
            Dim value As Object = cb.SelectedValue
    
            ' Mostramos el nombre del control junto con
            ' el valor de la propiedad obtenida.
            '
            Dim msg As String = String.Format("Nombre control: {0}{1}SelectedValue: {2}", _
                                              cb.Name, Environment.NewLine, value)
            MessageBox.Show(msg)
    
        End Sub
    
        Private Function GetData(cmd As SqlCommand) As DataTable
    
            If (cmd Is Nothing) Then
                Throw New ArgumentNullException("cmd")
            End If
    
            Using cnn As New SqlConnection(cadenaConexion)
                cmd.Connection = cnn
                Dim da As New SqlDataAdapter(cmd)
                Dim dt As New DataTable()
                da.Fill(dt)
                Return dt
            End Using
    
        End Function

    ¿Que en lugar de asignarle un objeto DataTable a la propiedad DataSource de los controles ComboBox deseas asignarle una lista genérica? Pues modifica el código y le asignas a cada uno de ellos la lista del tipo List(Of T) oportuna.

    Y para obtener la referencia de cualquier control ComboBox existente en un contenedor GroupBox, bien podrías hacer uso de la siguiente función:

        Private Function GetComboBox(name As String, parent As String) As ComboBox
    
            Dim lstGroupBox As List(Of GroupBox) = _
                (From ctrl As GroupBox In Me.Controls.OfType(Of GroupBox)() _
                 Where ctrl.Name = parent _
                 Select ctrl).ToList()
    
            If (lstGroupBox.Count = 0) Then Return Nothing
    
            Dim lstComboBox As List(Of ComboBox) = _
                (From ctrl As ComboBox In lstGroupBox(0).Controls.OfType(Of ComboBox)() _
                 Where ctrl.Name = name _
                 Select ctrl).ToList()
    
            If (lstComboBox.Count = 0) Then Return Nothing
    
            Return lstComboBox(0)
    
        End Function

    Cuando desees referenciar un control ComboBox por su nombre, llamarías a la función GetComboBox como indico a continuación:

        Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
    
            ' Seleccionamos el control llamado MyComboBox2 existente
            ' existente en el control GroupBox llamado MyGroupBox1.
            '
            Dim cb As ComboBox = GetComboBox("MyComboBox2", "MyGroupBox1")
    
            If (cb Is Nothing) Then
                MessageBox.Show("No existe el control ComboBox.")
                Return
            End If
    
            ' Obtenemos el valor de su propiedad SelectedValue
            '
            Dim value As Object = cb.SelectedValue
    
            ' Mostramos el nombre del control junto con
            ' el valor de la propiedad obtenida.
            '
            Dim msg As String = String.Format("Nombre control: {0}{1}SelectedValue: {2}", _
                                              cb.Name, Environment.NewLine, value)
            MessageBox.Show(msg)
    
        End Sub

    Esto muestra cómo podemos refenciar cualquier control mediante el valor de su propiedad Name. ;-)

    En fin, adapta el ejemplo a tus necesidades, comentándote que no conozco otra forma de crear controles en tiempo de ejecución, y menos de identificarlos, ya que se identifican por su propiedad Name o por un valor único que se le establezca a su propiedad Tag.

    Un saludo


    Enrique Martínez Montejo
            [MS MVP - VB]

    Nota informativa: La información contenida en este mensaje, así como el código fuente incluido en el mismo, se proporciona «COMO ESTÁ», sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, se inteligente y activa la instrucción
    Option Strict.



    domingo, 11 de mayo de 2014 7:05
    Moderador
  • "John Paz" escribió:

    > Ing. Enrique.

    Ya me hubiera gustado a mí tener una ingeniería, pero desgraciadamente no tengo ese título. :-(

    > tengo una duda, el codigo me recorre perfectamente los
    > textbox "Demandas" del groupbox , pero cuando termina
    > de recorrer estos textbox me entrega un 
    > MessageBox "Debe de establecer el valor del "  pero no
    > me dice el AccessibleName del textbox que esta recorriendo,
    > entonces no se cual textbox debo diligenciar o que dato falta...

    ¡Bueno! Incluí en el ejemplo ese "MessageBox" porque aparecía en el código de tu mensaje inicial, por tanto daba por hecho que tenías asignado un valor a la propiedad AccesibleName de cada control TextBox.

    > Te agradezco muchisimo que me ayudes a identificar el
    > textbox que me esta recorriendo.

    La verdad es que no sé muy bien para qué quieres utilizar la propiedad AccessibleName, salvo que te encuentres desarrollando una aplicación de accesibilidad, ya que si no hay nada escrito en el control TextBox, éste cambia su color de fondo a amarillo y se le pasa el foco.

    De todas maneras, al igual que le asignas un valor 1 a la propiedad Tag de cada control TextBox, tendrás que asignar igualmente el valor que deseas que tenga la propiedad AccessibleName de los controles TextBox, bien desde la Ventana de Propiedades, o si lo prefieres, también lo puedes establecer en tiempo de ejecución en el evento Load del formulario:

        TextBox1.AccessibleName = "Valor que deseas asignarle"
        TextBox2.AccessibleName = "Valor que deseas asignarle"


    Enrique Martínez
      [MS MVP - VB]

    Nota informativa: La información contenida en este mensaje, así como el código fuente incluido en el mismo, se proporciona «COMO ESTÁ», sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, activa la instrucción Option Strict.

    martes, 29 de mayo de 2012 5:58
    Moderador
  • En principio te diré que te vayas a la función ValidarDatos que aparece en el formulario 'Base Mano de Obra'. Si te fijas bien, ahí estás duplicando el código, porque primero estás ejecutando el código que en un principio tenías, y después estás ejecutando el código que yo te indiqué que ejecutaras.

    En dicha función comenta las siguientes líneas de código:

            'Dim Ctl As Control
            'Dim x As Integer
            'Periodos = Convert.ToSingle(ComboBox2.SelectedIndex)
            'For x = Me.Controls.Count - 1 To 0 Step -1
            '    Ctl = Me.Controls.Item(x)
            '    If TypeOf (Ctl) Is TextBox Then
            '        Dim Control As TextBox = Ctl
            '        If Control.Tag = 1 Then
            '            If Control.Text.Trim = "" Then
            '                MsgBox("Debe de establecer el valor del " & Control.AccessibleName)
            '                Control.Focus()
            '                ValidaDatos = False
            '                Exit Function
            '            Else
            '                Control.BackColor = Color.White
            '            End If
            '        End If
            '    End If
            'Next
          
    Y deja el que yo te indiqué:

         Dim ctrls As List(Of TextBox) = Me.GetTypeControls(Of TextBox)(Me, False)

         ' ....

         ' ....

    También, debes de sustituir la siguiente línea en dicha función. Donde ejecutas

         ' If (CInt(tb.Tag) <> 1) Then Continue For  --> Eliminar

    Tienes que ejecutar:

         If (Convert.ToString(tb.Tag) <> "1") Then Continue For

    porque parece ser que le has asignado un valor alfanumérico a la propiedad Tag de los controles ("1"), en lugar de asignarle un valor numérico (1), por lo que tienes que utilizar la función de conversión apropiada.

    Desde luego, por el vistazo rápido que le he echado al proyecto, el código fuente es mejorable. Veré lo que puedo hacer. ;-)


    Enrique Martínez
      [MS MVP - VB]

    Nota informativa: La información contenida en este mensaje, así como el código fuente incluido en el mismo, se proporciona «COMO ESTÁ», sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, activa la instrucción Option Strict.


    miércoles, 30 de mayo de 2012 16:44
    Moderador
  • "Pedro Avila" escribió:

    > Como veras el nombre del combo lo obtuve depurando y funciona, pero
    > el nombre lo debo obtener por código y supongamos que haya mas
    > ComboBox identifique a cada uno por su nombre y lo llene de datos.
    >

    Pedro, limítate a probar el ejemplo que te indiqué, tal cual está, en un nuevo proyecto de Visual Basic. Cuando comprendas su funcionamiento es cuando debes de adaptarlo a tu proyecto de C#. Pero si por casualidad pretendes que yo te haga la traducción del código a C#, en un foro de Visual Basic .net, me vas a perdonar pero va a ser que no, porque para eso ya hay bastantes "herramientas de traducción" de código por ahí, o también puedes acudir al foro de C# por si algún usuario del mismo te puede echar una mano en la traducción.

    > Como veras no estoy usando las variables de ese prodecimiento como
    > name y parent, no he sabido como usarlo, pq en el código uso Name y Parent.
    >
    >        /// <summary>
    >        /// Para obtener la referencia de cualquier control ComboBox existente en un contenedor GroupBox
    >         /// </summary>
    >         /// <param name="name">Nombre de CBO</param>
    >         /// <param name="parent">Nombre de GROUPBOX</param>
    >         /// <returns></returns>
    >         private EntitySelectorCombo GetComboBox(string name, string parent)
    >        {

    El código de la función GetComboBox que has publicado en tu mensaje, ¿lo has traducido tu o lo ha hecho una de esas "herramientas de traducción" existentes por Internet?

    Desde luego en nada se parece a mi función GetComboBox, y no lo digo porque la mía esté escrita en Visual Basic .net, si no porque para nada utilizo en ella funciones lambda ni otras "lindezas" parecidas, que si no estás muy acostumbrado a ellas, lo único que puede ocurrir es que pierdas el tiempo.

    Limítate a hacer la traducción correcta a C# de mi función GetComboBox, tal cual la publiqué en mi respuesta anterior, y deja las funciones lambda para otros menesteres. ;-)

    Dices que no sabes utilizar los parámetros 'name' y 'parent' del procedimiento GetComboBox. La verdad es que ignoro por completo el grado de conocimiento que tienes de C#, pero no hay mucho misterio para utilizar en C# un par de variables alfanuméricas (string) de la misma manera que se utilizan en Visual Basic .NET.

    Fíjate bien en la descripción de los parámetros 'name' y 'parent', porque lo único que tienes que hacer es pasarle el nombre del control ComboBox que deseas referenciar (name = "MyComboBox2"), así como el nombre del control GroupBox que lo contiene (parent = "MyGroupBox1"). Por supuesto, se comprende que la función GetComboBox la has insertado en el formulario que contiene el control GroupBox que has creado, bien en tiempo de diseño o de ejecución, ya que en la misma, lo primero que se hace es obtener el control GroupBox cuya propiedad Name se corresponda con el valor del parámetro 'parent' pasado al procedimiento, y se obtiene recorriendo la colección Controls del formulario ('Me' en Visual Basic o 'this' en C#).

    Si lo prefieres, sustituye los parámetros por estos otros:

        Private Function GetComboBox(nombreComboBox As String, nombreGroupBoxContenedor As String) As ComboBox
    

    Obviamente también tendrás que modificarlos en el cuerpo del procedimiento.

    Pedro, insisto que no hay mucho misterio para referenciar un control ComboBox, TextBox, Label, etc., existente en un contenedor Form, ComboBox o cualquier otro. Lo único que tienes que hacer es traducir correctamente a C# el código de mi función GetComboBox, tal cual está, y dejar las funciones lambda y ordenar los controles para una mejor ocasión.

    ¡Ojo! Que no estoy diciendo que las funciones lambda no sean útiles, pero para el caso que nos ocupa, opino que no hace falta utilizarlas. ;-)

    ¡Suerte!

    Enrique Martínez Montejo
            [MS MVP - VB]

    Nota informativa: La información contenida en este mensaje, así como el código fuente incluido en el mismo, se proporciona «COMO ESTÁ», sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, se inteligente y activa la instrucción
    Option Strict.

    lunes, 12 de mayo de 2014 10:10
    Moderador

Todas las respuestas

  • "John Paz" escribió:

    > antes que realice los calculos valide que todos los cambos han sido
    > diligenciados y mediante el siguiente codigo:
    >
    > For x = Me.Controls.Count - 1 To 0 Step -1
    >
    > Next
    >
    > Pero solo me valida los textbox que estan por fuera del groupbox,
    > quisiera saber si me puedes ayuda haciendo que tambien me valide
    > los textbox demandas que estan dentro del groupbox

    Hola, John:

    Si la palabra clave Me hace referencia al formulario donde tienes insertados tanto los controles TextBox como GroupBox, al recorrer el siguiente bucle:

      For x = Me.Controls.Count - 1 To 0 Step -1

    Únicamente obtendrás los controles que tienen como contenedor al formulario, que es lo que te está sucediendo. Para obtener los CONTROLES EXISTENTES ÚNICAMENTE EN EL CONTROL GROUPBOX, tendrías que recorrer su colección de controles:

            For Each ctrl As Control In GroupBox1.Controls


            Next

    Pero si deseas obtener todos los controles TextBox, con independencia que su contenedor sea un formulario, un control GroupBox o cualquier otro objeto contenedor, tienes que implementar una función que se llame a sí misma (de manera recursiva), para recorrer su posible colección Controls.

    Por ejemplo, podrías hacer uso de la siguiente función:

        ''' <summary>
        ''' Obtiene una colección con los controles de un determinado
        ''' tipo existentes en un contenedor superior.
        ''' </summary>
        ''' <typeparam name="T">Tipo de control que se desea obtener.</typeparam>
        ''' <param name="parentContainer">Objeto Control que actua de
        ''' contenedor para el tipo de control que se desea obtener.</param>
        ''' <param name="includeInheritedControls">Indica si se incluyen en la
        ''' colección aquellos controles que heredan de la clase especificada.</param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Function GetTypeControls(Of T As Control)( _
            parentContainer As Control, includeInheritedControls As Boolean) As List(Of T)
    
            If (parentContainer Is Nothing) Then Return Nothing
    
            Dim controls As New List(Of T)
    
            ' System.Type para el tipo de dato especificado.
            '
            Dim typeT As Type = GetType(T)
    
            For Each ctrl As Control In parentContainer.Controls
    
                If (includeInheritedControls) Then
                    If (TypeOf ctrl Is T) Then _
                        controls.Add(DirectCast(ctrl, T))
    
                Else
                    ' System.Type del control.
                    '
                    Dim typeControl As Type = ctrl.GetType()
                    If (typeControl.Equals(typeT)) Then _
                        controls.Add(DirectCast(ctrl, T))
    
                End If
    
                controls.AddRange(Me.GetTypeControls(Of T)(ctrl, includeInheritedControls))
    
            Next
    
            Return controls
    
        End Function

    Este método se encuentra basado en el siguiente ejemplo del compañero Lluís Franco:

    How to: Obtener controles de un formulario con generics

    Pero con la salvedad que el suyo utiliza el operador 'is' del lenguaje C# (que equivale al operador TypeOf de Visual Basic .net), con lo que se devolverán los controles de la clase especificada (TextBox en éste caso), más aquellos que hereden de la misma (aquellos que hereden de TextBox).

    Y como puede ocurrir que me interese obtener sólo los controles de un determinado tipo, no los que deriven de él, mi código obtiene el valor System.Type para igualar los controles existentes en la colección. No obstante, la función toma un segundo parámetro (includeInheritedControls) por si queremos incluir en la búsqueda aquellos controles que puedan heredar de la clase especificada.

    Dicho ésto, cuando desees recuperar todos los controles TextBox, ejecutarías lo siguiente:

            ' Obtenemos todos los controles TextBox que se encuentren
            ' tanto en el formulario como en cualquier otro control
            ' contenedor existente en el formulario actual.
            '
            Dim ctrls As List(Of TextBox) = Me.GetTypeControls(Of TextBox)(Me, False)
    
            For Each ctrl As Control In ctrls
    
                If (Not (TypeOf ctrl Is TextBox)) Then
                    ' Si el control no es del tipo TextBox,
                    ' continuamos el bucle.
                    '
                    Continue For
                End If
    
                ' El control es del tipo TextBox.
                '
                Dim tb As TextBox = DirectCast(ctrl, TextBox)
    
                ' Si el valor de la propiedad Tag es distinto 
                ' de 1, continuamos el bucle.
                '
                If (CInt(tb.Tag) <> 1) Then Continue For
    
                ' Verificamos si tiene algo escrito.
                '
                If (tb.Text.Trim() = String.Empty) Then
                    MessageBox.Show("Debe de establecer el valor del " & tb.AccessibleName)
                    tb.BackColor = Color.Yellow
                    tb.Focus()
                    ValidaDatos = False
                    Return
                End If
    
                ' Hay algo escrito en el contro.
                '
                tb.BackColor = Color.White
    
            Next

    Me imagino que estarás utilizando la versión 2.0 o superior del marco de trabajo de .NET (Visual Basic 2005 o superior), porque de no ser así, no vas a poder utilizar listas genéricas. ;-)

    Un saludo


    Enrique Martínez
      [MS MVP - VB]

    Nota informativa: La información contenida en este mensaje, así como el código fuente incluido en el mismo, se proporciona «COMO ESTÁ», sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, activa la instrucción Option Strict.


    domingo, 27 de mayo de 2012 7:54
    Moderador
  • Ing. Enrique.

    Muchisimas gracias por tu ayuda, gracias a ti avance en mi tesis, Ing. tengo una duda, el codigo me recorre perfectamente los textbox "Demandas" del groupbox , pero cuando termina de recorrer estos textbox me entrega un  MessageBox "Debe de establecer el valor del "  pero no me dice el AccessibleName del textbox que esta recorriendo,entonces no se cual textbox debo diligenciar o que dato falta... 

    Te agradezco muchisimo que me ayudes a identificar el textbox que me esta recorriendo.

    Sin otro particular.

    John Paz

    Desde Bogota, Colombia


    lunes, 28 de mayo de 2012 16:52
  • "John Paz" escribió:

    > Ing. Enrique.

    Ya me hubiera gustado a mí tener una ingeniería, pero desgraciadamente no tengo ese título. :-(

    > tengo una duda, el codigo me recorre perfectamente los
    > textbox "Demandas" del groupbox , pero cuando termina
    > de recorrer estos textbox me entrega un 
    > MessageBox "Debe de establecer el valor del "  pero no
    > me dice el AccessibleName del textbox que esta recorriendo,
    > entonces no se cual textbox debo diligenciar o que dato falta...

    ¡Bueno! Incluí en el ejemplo ese "MessageBox" porque aparecía en el código de tu mensaje inicial, por tanto daba por hecho que tenías asignado un valor a la propiedad AccesibleName de cada control TextBox.

    > Te agradezco muchisimo que me ayudes a identificar el
    > textbox que me esta recorriendo.

    La verdad es que no sé muy bien para qué quieres utilizar la propiedad AccessibleName, salvo que te encuentres desarrollando una aplicación de accesibilidad, ya que si no hay nada escrito en el control TextBox, éste cambia su color de fondo a amarillo y se le pasa el foco.

    De todas maneras, al igual que le asignas un valor 1 a la propiedad Tag de cada control TextBox, tendrás que asignar igualmente el valor que deseas que tenga la propiedad AccessibleName de los controles TextBox, bien desde la Ventana de Propiedades, o si lo prefieres, también lo puedes establecer en tiempo de ejecución en el evento Load del formulario:

        TextBox1.AccessibleName = "Valor que deseas asignarle"
        TextBox2.AccessibleName = "Valor que deseas asignarle"


    Enrique Martínez
      [MS MVP - VB]

    Nota informativa: La información contenida en este mensaje, así como el código fuente incluido en el mismo, se proporciona «COMO ESTÁ», sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, activa la instrucción Option Strict.

    martes, 29 de mayo de 2012 5:58
    Moderador
  • Ing. Enrique.

    Asi digas que no tienes este titulo sabes muchisimo mas que algunos ingenieros que conozco, Ingeniero los textbox que se crean son dinamicos, por ejemplo yo selecciono en un combobox el numero de periodos y eso se traduce en el numero textbox que me aparecen en el groupbox, y cada uno de ellos tiene como AccessibleName "Demanda 1", "Demanda 2", etc, pero lo que me ocurre es lo siguiente, yo seleccione 4 periodos en el combobox, efectivamente me aparecen 4 textbox en el groupbox, diligencio el textbox 1 y 2 pero el 3 y el 4 no, despues oprimo el boton CALCULAR, y me aparece en un Msgbox "debe diligenciar la demanda del perido 3" la diligencio y oprimo CALCULAR me dice"debe diligenciar la demanda del perido 4", oprimo CALCULAR y me dice "debe diligenciar " pero no me dice de que item, y en el groupbox no veo que ponga en foco ninguno, por ende no se cual falta por diligenciar, intente adicionando en el msgbox el nombre del objeto pero me aparece es el nombre del formulario, y con el tab me aparece "0", entonces no se que hacer...agradezco tu ayuda, cuando tenga mi tesis de ingenieria terminada, estaras dentro de mis agradecimientos..ya lo veras

    Att:

    John Paz

    martes, 29 de mayo de 2012 12:41
  • Tenías que haber especificado el código que ejecutas para crear los controles TextBox de manera dinámica.

    Inicia un nuevo proyecto y en el formulario de inicio inserta dos controles Button y un control GroupBox. Añade al mismo el código de la función GetTypeControls que te indiqué en un mensaje anterior, y en el evento Click del primer control Button, inserta el siguiente código:

        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button4.Click
    
            ' Creamos tres controles TextBox
            '
            For index As Integer = 1 To 3
    
                Dim tb As New TextBox()
    
                ' Establecemos el nombre del control
                '
                tb.Name = String.Format("Demanda{0}", index)
    
                ' Le asignamos un valor a la propiedad Tag.
                '
                tb.Tag = 1
    
                ' A su propiedad AccessibleName le asignamos
                ' el nombre del control.
                '
                tb.AccessibleName = tb.Name
    
                ' Indicamos la posición del control.
                '
                tb.Location = New Point(3, 25 * index)
    
                ' Lo añadimos a su contenedor, en éste caso
                ' a un control GroupBox.
                '
                tb.Parent = GroupBox1
    
            Next
    
        End Sub

    Al crear los controles dinámicamente, no queda más remedio que configurar el valor de sus propiedades en tiempo de ejecución. En éste ejemplo le estoy asignando a la propiedad AccessibleName el mismo valor que tiene la propiedad Name, porque no sé qué valor asignarle. Pero creo que es suficiente para mostrar cómo lo tienes que hacer.

    Ahora, en el evento Click del segundo control Button, inserta el código para comprobar si se ha escrito algo en los controles TextBox:

        Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
    
            ' Obtenemos todos los controles TextBox que se encuentren
            ' tanto en el formulario como en cualquier otro control
            ' contenedor existente en el formulario actual.
            '
            Dim ctrls As List(Of TextBox) = GetTypeControls(Of TextBox)(Me, False)
    
            For Each ctrl As Control In ctrls
    
                If (Not (TypeOf ctrl Is TextBox)) Then
                    ' Si el control no es del tipo TextBox,
                    ' continuamos el bucle.
                    '
                    Continue For
                End If
    
                ' El control es del tipo TextBox.
                '
                Dim tb As TextBox = DirectCast(ctrl, TextBox)
    
                ' Si el valor de la propiedad Tag es distinto 
                ' de 1, continuamos el bucle.
                '
                If (CInt(tb.Tag) <> 1) Then Continue For
    
                ' Verificamos si tiene algo escrito.
                '
                If (tb.Text.Trim() = String.Empty) Then
                    MessageBox.Show("Debe de establecer el valor del " & tb.AccessibleName)
                    tb.BackColor = Color.Yellow
                    tb.Focus()
                    ValidaDatos = False
                    Return
                End If
    
                ' Hay algo escrito en el contro.
                '
                tb.BackColor = Color.White
    
            Next
    
        End Sub

    Como podrás ver, es el mismo código que te indiqué en mi primera respuesta. Cuando pulses el segundo control Button (aquel al que parece ser tu le llamas CALCULAR), aparecerá en amarillo el color de fondo de aquellos controles TextBox donde no se haya escrito nada.


    Enrique Martínez
      [MS MVP - VB]

    Nota informativa: La información contenida en este mensaje, así como el código fuente incluido en el mismo, se proporciona «COMO ESTÁ», sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, activa la instrucción Option Strict.



    martes, 29 de mayo de 2012 15:17
    Moderador
  • Ing. Muchisimas gracias por la ayuda, pero los textbox se crean dinamicamente con el evento changed de un combobox, Inge, mira que probe ayer y encontre algo extraño, pues yo selecciono 3 en el combobox y cuando le doy calcular, me dice "debe diligenciar  " y me manda al foco del siguiente textbox osea el 4, sin uncluso haberlo seleccionado, Te puedo enviar el archivo y me ayudas con una revision sencillta?? te agradeceria infinitamente...
    miércoles, 30 de mayo de 2012 15:28
  • "John Paz" escribió:

    > los textbox se crean dinamicamente con el evento changed de un combobox,
    > Inge, mira que probe ayer y encontre algo extraño, pues yo selecciono 3
    > en el combobox y cuando le doy calcular, me dice "debe diligenciar  "
    > y me manda al foco del siguiente textbox osea el 4, sin uncluso haberlo
    > seleccionado, ...

    Sin ver lo que estás haciendo, y cómo lo estás haciendo, es complicado intentar ayudarte. ¿Has iniciado un nuevo proyecto, a modo de prueba, para ejecutar el código que te indiqué en mi último mensaje?


    Enrique Martínez
      [MS MVP - VB]

    Nota informativa: La información contenida en este mensaje, así como el código fuente incluido en el mismo, se proporciona «COMO ESTÁ», sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, activa la instrucción Option Strict.




    miércoles, 30 de mayo de 2012 15:50
    Moderador
  • Inge Listo ya te envie el archivo , gracias por tan importante ayuda....
    miércoles, 30 de mayo de 2012 16:20
  • He recibido el proyecto. Pero hoy ya va a ser imposible que te pueda decir algo, porque tengo que hacer otras cuestiones personales. Procuraré que mañana tengas noticias.

    Por cierto, vivo en Jaén (España), aunque tomo nota de la invitación que me has efectuado. :-D


    Enrique Martínez
      [MS MVP - VB]

    Si usas Visual Basic .NET y deseas ser productivo y feliz, activa la instrucción Option Strict.


    miércoles, 30 de mayo de 2012 16:28
    Moderador
  • En principio te diré que te vayas a la función ValidarDatos que aparece en el formulario 'Base Mano de Obra'. Si te fijas bien, ahí estás duplicando el código, porque primero estás ejecutando el código que en un principio tenías, y después estás ejecutando el código que yo te indiqué que ejecutaras.

    En dicha función comenta las siguientes líneas de código:

            'Dim Ctl As Control
            'Dim x As Integer
            'Periodos = Convert.ToSingle(ComboBox2.SelectedIndex)
            'For x = Me.Controls.Count - 1 To 0 Step -1
            '    Ctl = Me.Controls.Item(x)
            '    If TypeOf (Ctl) Is TextBox Then
            '        Dim Control As TextBox = Ctl
            '        If Control.Tag = 1 Then
            '            If Control.Text.Trim = "" Then
            '                MsgBox("Debe de establecer el valor del " & Control.AccessibleName)
            '                Control.Focus()
            '                ValidaDatos = False
            '                Exit Function
            '            Else
            '                Control.BackColor = Color.White
            '            End If
            '        End If
            '    End If
            'Next
          
    Y deja el que yo te indiqué:

         Dim ctrls As List(Of TextBox) = Me.GetTypeControls(Of TextBox)(Me, False)

         ' ....

         ' ....

    También, debes de sustituir la siguiente línea en dicha función. Donde ejecutas

         ' If (CInt(tb.Tag) <> 1) Then Continue For  --> Eliminar

    Tienes que ejecutar:

         If (Convert.ToString(tb.Tag) <> "1") Then Continue For

    porque parece ser que le has asignado un valor alfanumérico a la propiedad Tag de los controles ("1"), en lugar de asignarle un valor numérico (1), por lo que tienes que utilizar la función de conversión apropiada.

    Desde luego, por el vistazo rápido que le he echado al proyecto, el código fuente es mejorable. Veré lo que puedo hacer. ;-)


    Enrique Martínez
      [MS MVP - VB]

    Nota informativa: La información contenida en este mensaje, así como el código fuente incluido en el mismo, se proporciona «COMO ESTÁ», sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, activa la instrucción Option Strict.


    miércoles, 30 de mayo de 2012 16:44
    Moderador
  • Hola @Enrique

    Si tuvieras en un contenedor groupBox dos comboBox como los identificarias para que en su propiedad datasource pasarle una lista de datos.

    Pero imaginando que esos controles ComboBox se crearon en tiempo de ejecución.

     

    Pedro Ávila
    "El hombre sabio querrá estar siempre con quien sea mejor que él."
    Lima - Perú

    sábado, 10 de mayo de 2014 20:18
  • "Pedro Ávila (MAP)" preguntó:

    > Hola @Enrique
    >
    > Si tuvieras en un contenedor groupBox dos comboBox como los
    > identificarias para que en su propiedad datasource pasarle
    > una lista de datos.
    >
    > Pero imaginando que esos controles ComboBox se crearon en
    > tiempo de ejecución.

    Pedro, en Visual Basic .NET, C#, y me imagino que igual sucederá en cualquier otro lenguaje .NET, todos los controles se crean en tiempo de ejecución, porque cuando arrastramos un control al formulario en tiempo de diseño, lo que hace el IDE de Visual Studio es escribir el código necesario en el procedimiento InitializeComponent del formulario para que ese control se cree correctamente en tiempo de ejecución. ¿Que no deseas arrastrar el control al formulario en tiempo de diseño? Me parece estupendo, pero tendrás que hacer lo mismo que hace el IDE para identificar un control, que es establecer el valor oportuno a su propiedad Name, de igual manera que identificamos a una persona cualquiera por su nombre, porque de no hacerlo de esa manera, ¿cómo pretendes identificar un control, sea ComboBox o TextBox?

    También podrías establecerle un valor adecuado a la propiedad Tag para identificar al control ComboBox. Pero si te es suficiente con el valor de la propiedad Name, ¿para qué asignar un valor Object a la propiedad Tag que posteriormente tendrás que convertir al tipo de dato correcto?

    La diferencia está en que mientras que creamos el control en tiempo de diseño, disponemos de una variable objeto que es reconocida por el IDE, y por tanto, por la característa intellisense de Visual Studio, no así cuando creamos el control en tiempo de ejecución, ya que aquí intellisense nos va a servir de bien poco. ;-)

    El siguiente ejemplo crea en tiempo de ejecución un control GroupBox y dos controles ComboBox. Asimismo se configura la propiedad DataSource de ambos controles, y le añade el controlador para el evento SelectedIndexChanged de los mismos:

        Private Sub Button5_Click(sender As Object, e As EventArgs) Handles Button5.Click
    
            ' Creamos y configuramos un control GroupBox.
            '
            Dim gb As New GroupBox()
    
            gb.Name = "MyGroupBox1" ' Le asignamos su nombre.
            gb.Location = New Point(20, 50)
            gb.Size = New Size(500, 200)
    
            ' Creamos y configuramos un nuevo control ComboBox.
            '
            Dim cb As ComboBox = CreateComboBox("MyComboBox1", New Point(30, 30), New Size(200, 25))
    
            ' Configuramos el enlace a datos.
            '
            Dim cmd As New SqlCommand()
            cmd.CommandText = "SELECT IdFactura, IdCliente FROM Facturas"
    
            cb.DataSource = GetData(cmd)
            cb.DisplayMember = "IdFactura"
            cb.ValueMember = "IdCliente"
    
            ' Lo añadimos al control GroupBox creado anteriormente.
            '
            cb.Parent = gb
    
            ' Configuramos un segundo control ComboBox.
            '
            cb = CreateComboBox("MyComboBox2", New Point(250, 30), New Size(200, 25))
    
            ' Configuramos el enlace a datos.
            '
            cmd = New SqlCommand()
            cmd.CommandText = "SELECT IdCliente, Nombre FROM Clientes"
    
            cb.DataSource = GetData(cmd)
            cb.DisplayMember = "Nombre"
            cb.ValueMember = "IdCliente"
    
            ' Lo añadimos al control GroupBox creado anteriormente.
            '
            cb.Parent = gb
    
            ' Por último, añadimos el control GroupBox al formulario.
            '
            gb.Parent = Me
    
        End Sub
    
        Private Function CreateComboBox(name As String, location As Point, size As Size) As ComboBox
    
            Dim cb As New ComboBox()
            cb.Name = name
            cb.Location = location
            cb.Size = size
    
            ' Establecemos el controlador para su evento SelectedIndexChanged.
            '
            AddHandler cb.SelectedIndexChanged, AddressOf ComboBoxOnSelectedIndexChanged
    
            Return cb
    
        End Function
    
        Private Sub ComboBoxOnSelectedIndexChanged(sender As Object, e As EventArgs)
    
            ' Obtenemos la referencia al control ComboBox
            ' que ha desencadenado el evento.
            '
            Dim cb As ComboBox = DirectCast(sender, ComboBox)
    
            ' Obtenemos el valor de su propiedad SelectedValue
            '
            Dim value As Object = cb.SelectedValue
    
            ' Mostramos el nombre del control junto con
            ' el valor de la propiedad obtenida.
            '
            Dim msg As String = String.Format("Nombre control: {0}{1}SelectedValue: {2}", _
                                              cb.Name, Environment.NewLine, value)
            MessageBox.Show(msg)
    
        End Sub
    
        Private Function GetData(cmd As SqlCommand) As DataTable
    
            If (cmd Is Nothing) Then
                Throw New ArgumentNullException("cmd")
            End If
    
            Using cnn As New SqlConnection(cadenaConexion)
                cmd.Connection = cnn
                Dim da As New SqlDataAdapter(cmd)
                Dim dt As New DataTable()
                da.Fill(dt)
                Return dt
            End Using
    
        End Function

    ¿Que en lugar de asignarle un objeto DataTable a la propiedad DataSource de los controles ComboBox deseas asignarle una lista genérica? Pues modifica el código y le asignas a cada uno de ellos la lista del tipo List(Of T) oportuna.

    Y para obtener la referencia de cualquier control ComboBox existente en un contenedor GroupBox, bien podrías hacer uso de la siguiente función:

        Private Function GetComboBox(name As String, parent As String) As ComboBox
    
            Dim lstGroupBox As List(Of GroupBox) = _
                (From ctrl As GroupBox In Me.Controls.OfType(Of GroupBox)() _
                 Where ctrl.Name = parent _
                 Select ctrl).ToList()
    
            If (lstGroupBox.Count = 0) Then Return Nothing
    
            Dim lstComboBox As List(Of ComboBox) = _
                (From ctrl As ComboBox In lstGroupBox(0).Controls.OfType(Of ComboBox)() _
                 Where ctrl.Name = name _
                 Select ctrl).ToList()
    
            If (lstComboBox.Count = 0) Then Return Nothing
    
            Return lstComboBox(0)
    
        End Function

    Cuando desees referenciar un control ComboBox por su nombre, llamarías a la función GetComboBox como indico a continuación:

        Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
    
            ' Seleccionamos el control llamado MyComboBox2 existente
            ' existente en el control GroupBox llamado MyGroupBox1.
            '
            Dim cb As ComboBox = GetComboBox("MyComboBox2", "MyGroupBox1")
    
            If (cb Is Nothing) Then
                MessageBox.Show("No existe el control ComboBox.")
                Return
            End If
    
            ' Obtenemos el valor de su propiedad SelectedValue
            '
            Dim value As Object = cb.SelectedValue
    
            ' Mostramos el nombre del control junto con
            ' el valor de la propiedad obtenida.
            '
            Dim msg As String = String.Format("Nombre control: {0}{1}SelectedValue: {2}", _
                                              cb.Name, Environment.NewLine, value)
            MessageBox.Show(msg)
    
        End Sub

    Esto muestra cómo podemos refenciar cualquier control mediante el valor de su propiedad Name. ;-)

    En fin, adapta el ejemplo a tus necesidades, comentándote que no conozco otra forma de crear controles en tiempo de ejecución, y menos de identificarlos, ya que se identifican por su propiedad Name o por un valor único que se le establezca a su propiedad Tag.

    Un saludo


    Enrique Martínez Montejo
            [MS MVP - VB]

    Nota informativa: La información contenida en este mensaje, así como el código fuente incluido en el mismo, se proporciona «COMO ESTÁ», sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, se inteligente y activa la instrucción
    Option Strict.



    domingo, 11 de mayo de 2014 7:05
    Moderador
  • Hola @Enrique

    He corregido el código que tenía y seguí tu consejo a cada combo le pongo un nombre para poder identificarlo.

    El nombre se lo asigno como vez en tiempo de ejecución concatenando cbo + la variable indice_CBO++ incrementándose la variable cada vez que agregue un nuevo combo así si agrego otro combo se llamara cbo1.

    El EntitySelectorCombo es un ComboBox que personalice por eso tiene ese nombre.

    Este es el código que creo en ComboBox(EntitySelectoCombo)

    private EntitySelectorCombo CrearComboBox(bool vbool)
            {
                EntitySelectorCombo _combo = new EntitySelectorCombo();
    
                _combo.Size = new Size(102, 20);
                _combo.Top = indice_CBO * 25 + 85;
                _combo.Left = 135;
                _combo.Name = "cbo" + indice_CBO;
                _combo.Visible = vbool;
                _combo.DropDownStyle = ComboBoxStyle.DropDownList;
        
                indice_CBO++;
    
                return _combo;
            }


    Esto es para referenciar cualquier control ComboBox

    /// <summary>
            /// Para obtener la referencia de cualquier control ComboBox existente en un contenedor GroupBox
            /// </summary>
            /// <param name="name">Nombre de CBO</param>
            /// <param name="parent">Nombre de GROUPBOX</param>
            /// <returns></returns>
            private EntitySelectorCombo GetComboBox(string name, string parent)
            {
                List<GroupBox> lstGroupBox = new List<GroupBox>(this.Controls.OfType<GroupBox>().OrderBy(x => x.Parent));
                
                if ((lstGroupBox.Count == 0))
                    return null;
    
                List<EntitySelectorCombo> lstComboBox =
                    new List<EntitySelectorCombo>(lstGroupBox[0].Controls.OfType<EntitySelectorCombo>().OrderBy(x => x.Name));
    
                
    	        if ((lstComboBox.Count == 0))
    		        return null;
    
                return lstComboBox[0];
            }


    Como veras no estoy usando las variables de ese prodecimiento como name y parent, no he sabido como usarlo, pq en el código uso Name y Parent.

    Para ser mas ordenado yo, te cuento que para poder crear los controles hago una consulta a la base de datos, en la cual tengo los campos lTexto, lCmb, lCheck en los cuales en esos campos los manejo con 1 ó 0 dependiendo si quiero crear el control.

    private void GenerarPropiedades()
            {
                List<ItemEntity> lista = new List<ItemEntity>();
                lista = Item.GetItemPropiedades(idItem); ==> Acá traigo los valores para que se activen los controles
    
                foreach (var prop in lista)
                {
                    
                    if(!string.IsNullOrEmpty(prop.NomItem))
                    {
                        groupBox1.Controls.Add(CrearLabel(prop.NomItem));
                    }
                    
                    if(Convert.ToBoolean(prop.lText) != false)
                    {
                        groupBox1.Controls.Add(CrearTexBox(prop.Abrev, Convert.ToBoolean(prop.lText)));
                    }
                    
                    if(Convert.ToBoolean(prop.lCmb) != false)
                    {
                        groupBox1.Controls.Add(CrearComboBox(Convert.ToBoolean(prop.lCmb)));
                    }
    
                    if(Convert.ToBoolean(prop.lChek) != false)
                    {
                        groupBox1.Controls.Add(CrearCheckBox(Convert.ToBoolean(prop.lChek)));
                    }
    
                    List<sItemEntity> listaCombo = Item.CargarComboMatriz(prop.It_Id, prop.Item_Id);
    
                    List<EntitySelectorCombo> lstComboBox =
                    new List<EntitySelectorCombo>(groupBox1.Controls.OfType<EntitySelectorCombo>().OrderBy(x => x.Name));
    		// Con lstComboBox intento obtener el nombre del combo que esta en el GroupBox, pero me arroja un control cbo.
                    foreach (var item in lstComboBox)
                    {
                        item.Name;
                    }
                    //Depurando vi que elcombo se llama cbo0, es por eso que le puse el nombre.
                    EntitySelectorCombo cb = GetComboBox("cbo0", "groupBox1"); => Llamo a la función GetCombo.
    
                    if (cb != null & listaCombo.Count != 0)
                    {
                        cb.DataSource = listaCombo; ==> Cargo el control con datos
                    }
                } 
            }

    Como veras el nombre del combo lo obtuve depurando y funciona, pero el nombre lo debo obtener por código y supongamos que haya mas ComboBox identifique a cada uno por su nombre y lo llene de datos.

    Son los controles creados dentro del GroupBox y el ComboBox cargado de datos, luego que afine esto de identificarlos por nombre, tendré que identificarlos todos los controles por su nombre par poder guardar los datos en la DB.

    @Enrique te pido mil disculpas por poner el código que no es correspondiente a este foro y sabiendo que no debo, pero quería mostrarte para tener un mejor panorama de lo que deseo hacer y mostrarte las técnicas usadas que me recomiendas.


    Pedro Ávila
    "El hombre sabio querrá estar siempre con quien sea mejor que él."
    Lima - Perú




    • Editado Pedro Ávila domingo, 11 de mayo de 2014 18:16 xxxxxxxxxxxx
    domingo, 11 de mayo de 2014 18:09
  • "Pedro Avila" escribió:

    > Como veras el nombre del combo lo obtuve depurando y funciona, pero
    > el nombre lo debo obtener por código y supongamos que haya mas
    > ComboBox identifique a cada uno por su nombre y lo llene de datos.
    >

    Pedro, limítate a probar el ejemplo que te indiqué, tal cual está, en un nuevo proyecto de Visual Basic. Cuando comprendas su funcionamiento es cuando debes de adaptarlo a tu proyecto de C#. Pero si por casualidad pretendes que yo te haga la traducción del código a C#, en un foro de Visual Basic .net, me vas a perdonar pero va a ser que no, porque para eso ya hay bastantes "herramientas de traducción" de código por ahí, o también puedes acudir al foro de C# por si algún usuario del mismo te puede echar una mano en la traducción.

    > Como veras no estoy usando las variables de ese prodecimiento como
    > name y parent, no he sabido como usarlo, pq en el código uso Name y Parent.
    >
    >        /// <summary>
    >        /// Para obtener la referencia de cualquier control ComboBox existente en un contenedor GroupBox
    >         /// </summary>
    >         /// <param name="name">Nombre de CBO</param>
    >         /// <param name="parent">Nombre de GROUPBOX</param>
    >         /// <returns></returns>
    >         private EntitySelectorCombo GetComboBox(string name, string parent)
    >        {

    El código de la función GetComboBox que has publicado en tu mensaje, ¿lo has traducido tu o lo ha hecho una de esas "herramientas de traducción" existentes por Internet?

    Desde luego en nada se parece a mi función GetComboBox, y no lo digo porque la mía esté escrita en Visual Basic .net, si no porque para nada utilizo en ella funciones lambda ni otras "lindezas" parecidas, que si no estás muy acostumbrado a ellas, lo único que puede ocurrir es que pierdas el tiempo.

    Limítate a hacer la traducción correcta a C# de mi función GetComboBox, tal cual la publiqué en mi respuesta anterior, y deja las funciones lambda para otros menesteres. ;-)

    Dices que no sabes utilizar los parámetros 'name' y 'parent' del procedimiento GetComboBox. La verdad es que ignoro por completo el grado de conocimiento que tienes de C#, pero no hay mucho misterio para utilizar en C# un par de variables alfanuméricas (string) de la misma manera que se utilizan en Visual Basic .NET.

    Fíjate bien en la descripción de los parámetros 'name' y 'parent', porque lo único que tienes que hacer es pasarle el nombre del control ComboBox que deseas referenciar (name = "MyComboBox2"), así como el nombre del control GroupBox que lo contiene (parent = "MyGroupBox1"). Por supuesto, se comprende que la función GetComboBox la has insertado en el formulario que contiene el control GroupBox que has creado, bien en tiempo de diseño o de ejecución, ya que en la misma, lo primero que se hace es obtener el control GroupBox cuya propiedad Name se corresponda con el valor del parámetro 'parent' pasado al procedimiento, y se obtiene recorriendo la colección Controls del formulario ('Me' en Visual Basic o 'this' en C#).

    Si lo prefieres, sustituye los parámetros por estos otros:

        Private Function GetComboBox(nombreComboBox As String, nombreGroupBoxContenedor As String) As ComboBox
    

    Obviamente también tendrás que modificarlos en el cuerpo del procedimiento.

    Pedro, insisto que no hay mucho misterio para referenciar un control ComboBox, TextBox, Label, etc., existente en un contenedor Form, ComboBox o cualquier otro. Lo único que tienes que hacer es traducir correctamente a C# el código de mi función GetComboBox, tal cual está, y dejar las funciones lambda y ordenar los controles para una mejor ocasión.

    ¡Ojo! Que no estoy diciendo que las funciones lambda no sean útiles, pero para el caso que nos ocupa, opino que no hace falta utilizarlas. ;-)

    ¡Suerte!

    Enrique Martínez Montejo
            [MS MVP - VB]

    Nota informativa: La información contenida en este mensaje, así como el código fuente incluido en el mismo, se proporciona «COMO ESTÁ», sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, se inteligente y activa la instrucción
    Option Strict.

    lunes, 12 de mayo de 2014 10:10
    Moderador
  • Gracias, @Enrique corregí el código.

    Pedro Ávila
    "El hombre sabio querrá estar siempre con quien sea mejor que él."
    Lima - Perú

    martes, 13 de mayo de 2014 15:04