none
Guardar valores de un ComboBox

    Pregunta

  • Hola! escribo para hacer una nueva consulta, en esta ocación sobre el combobox. Necesito mostrar en un formulario de alta de proveedores un combobox cargado con los nombres de cuentas que tengo almacenado en una tabla (cuentas) de la BD (Sql Server), pero al dar de alta el proveedor necesito guardar en la tabla de proveedores el Id de la cuenta que seleccione en el combobox, y no el nombre de la cuenta que figura en el combo.

    Para cargar el combobox tengo este código. Que si carga correctamente los nombres de cuenta.

    ComboBox1.DataSource = Cuentas.mostrarCuentas()
    ComboBox1.DisplayMember = "Cuenta"
    ComboBox1.ValueMember = "IdCuenta"

    Para guardar el proveedor, utilizo este linea de código pero no me guarda el IdCuenta de la tabla cuentas, sino la posición del elemento que selecciono en el combobox.

    Proveedor.IdCuenta = ComboBox1.SelectedValue

    Si pongo

    Proveedor.IdCuenta = ComboBox1.ValueMember

    Me salta el error "La conversión de la cadena "Idcuenta" en el tipo integer no es válida".

    Yo a IdCuenta lo tengo definido como Integer.

    También necesito mostrar en un label la descripción de la cuenta (que es otra columna o atributo de la tabla cuentas) que seleccione en el combobox.

    Cómo podría hacer?

    Muchas gracias por su ayuda.

    Saludos.



    viernes, 26 de agosto de 2016 9:36

Respuestas

  • Hola The High Road,

    Te recomendaría el uso del evento SelectionChangeCommitted del ComboBox en vez del SelectedIndexChanged.

    [-] ... Code

    Public Function VerDetalle(ByVal id As Integer) As Proveedores
            Dim cmd As New SqlCommand
            cmd.Parameters.AddWithValue("@IdCuenta", id)
    ....


    No entiendo la necesidad de retornar un valor de tipo Proveedores, si sólo vas a mandar un solo dato. Además deberías usar el ExecuteScalar ya que sólo obtienes un dato. Además el orden como declaras los valores en el método no es el adecuado.

    Ojo : El error que muestras talvéz se deba a que envías un parámetro erróneo. Mira los nombres :

    En la consulta solicitas una variable @IdConcepto pero le envías un @IdCuenta.

    Public Function VerDetalle(ByVal id As Integer) As Proveedores
            Using con As New SqlConnection(CadenaConexion)
                con.Open()
    
                Dim sql As String = "SELECT Detalle FROM Cuentas WHERE IdConcepto = @IdConcepto"
                Dim cmd As New SqlCommand(sql, con)
                cmd.Parameters.AddWithValue("@IdCuenta", id)
    
                Dim datos As New Proveedores
                datos.Detalle = CStr(cmd.ExecuteScalar())
    
                Return datos
            End Using
        End Function

    Saludos.


    JC NaupaCrispín
    Lima - Perú

    La magia no existe, la programación SI

    • Marcado como respuesta The High Road domingo, 28 de agosto de 2016 8:49
    sábado, 27 de agosto de 2016 14:05
  • The High Road,

    A ver, déjame hacerte llegar algunas consideraciones respecto al código mostrado:

    Primero, atiende la sugerencia de usar el evento SelectionChangeCommit en vez del evento SelectedIndexChanged cuando busques accionar código sólo cuando el usuario selecciona un elemento del desplegable, el evento SelectedIndexChanged se lanza incluso cuando el índice del elemento cambia mediante código, lo que podría acarrear resultados no esperados.

    Segundo, en la capa de UI veo que declaras la variable Proveedor de tipo Proveedores pero no veo que la instancies. Si no instancias la variable 'Proveedor' no podrás tener un objeto de tipo Proveedores y menos acceder a sus miembros.

    Dim Proveedor As New Proveedores

    Tercero,  noto que la capa de lógica de negocios implementa en la firma el modificador Friend, sin embargo la capa de acceso a datos implementa clases de instancia, ¿hay alguna explicación al respecto? Pienso que la capa de acceso a datos también debería implementar clases con el modificador Friend o ambas capas implementar clases de instancia y no porque sea una buena práctica sino porque no tiene sentido que una capa defina clases de instancia y la otra no, salvo que exista alguna explicación.

    Cuarto, en la capa de acceso a datos, el procedimiento de tipo Function llamado VerDetalle() retorna un tipo Proveedores, la consulta de selección filtra por el valor del parámetro @IdConcepto sin embargo tu cargas al objeto Command un valor para el parámetro @IdCuenta que no existe en el contexto de la consulta, ¿está mal definido el filtro en la consulta sql?, ¿está mal definido el nombre del parámetro que agregas al objeto Command?.

    Quinto, sobre el punto anterior, ¿el tipo Proveedores sólo tiene un miembro (propiedad Detalle)? Entiendo que debería tener más propiedades y todas ellas -salvo tengan el atributo NULLABLE- deberían establecer su valor a partir del objeto DataReader, caso contrario bastaría con recuperar el valor mediante el método ExecuteScalar(), sin embargo tengo mis dudas.

    Sexto, respecto al error, ¿donde es que interviene el tipo Conceptos?, ¿puedes detectar en que línea es que ocurre la excepción?


    Espero que la información proporcionada te haya sido de utilidad, quedo atento a tus comentarios.
    • Marcado como respuesta The High Road domingo, 28 de agosto de 2016 8:49
    sábado, 27 de agosto de 2016 16:33

Todas las respuestas

  • The High Road,

    La propiedad ValueMember recupera los valores -de la columna asignada- que sirven de "valor identificador" para cada elemento del desplegable, no obtiene valores de posición, quizá si los valores de la columna 'IdCuenta' son auto-numéricos confundas con un ordinal de posición.

    ¿Qué pasa si a la propiedad DisplayMember le asignas el valor de la columna 'IdCuenta'? ¿Puedes ver los valores correctos? Pues serán los mismos valores que recuperes con el método SelectedValue cuando selecciones un elemento.

    ComboBox1.DataSource = Cuentas.mostrarCuentas()
    ComboBox1.DisplayMember = "IdCuenta"
    ComboBox1.ValueMember = "IdCuenta"

    {!}- También necesito mostrar en un label la descripción de la cuenta (que es otra columna o atributo de la tabla cuentas) que seleccione en el combobox.

    Queda claro que vasa tener que hacer otra consulta de selección contra la base de datos para recuperar dicho valor a razón del elemento seleccionado. Para recuperar un sólo valor puedes hacer uso del método ExecuteScalar().


    Espero que la información proporcionada te haya sido de utilidad, quedo atento a tus comentarios.
    viernes, 26 de agosto de 2016 14:47
  • Willams Morales, gracias por responder. Tienes razón, el código que tenia para guardar el valor del item seleccionado en el combobox estaba bien, el problema era que tenia en true la propiedad sorted. Eso ya esta solucionado.

    Lo que no pude hacer el es mostrar en el label la descripción de la cuenta seleccionada.

    Tengo el siguiente código:

    Capa 1:

        Private Sub ComboBox1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ComboBox1.SelectedIndexChanged
            Dim Proveedor As Proveedores
            Proveedor = ProveedoresD.VerDetalle(ComboBox1.SelectedValue)
            Label5.Text = Proveedor.Detalle
            Label5.Visible = True
        End Sub

    Capa 2:

     Public Shared Function VerDetalle(ByVal id As Integer) As Proveedores
            Dim Proveedor2 As New ProveedoresD
            Return Proveedor2.VerDetalle(id)
        End Function

    Capa 3 (datos):

    Public Function VerDetalle(ByVal id As Integer) As Proveedores
            Dim cmd As New SqlCommand
            cmd.Parameters.AddWithValue("@IdCuenta", id)
            cmd.CommandText = "SELECT Detalle FROM Cuentas WHERE IdConcepto = @IdConcepto"
            cmd.Connection = New SqlConnection(CadenaConexion)
            cmd.Connection.Open()
            Dim oreader As SqlDataReader = cmd.ExecuteReader()
            Dim datos As New Proveedores
            If oreader.Read Then
                datos.Detalle = oreader("Detalle")
                cmd.Connection.Close()
            End If
            Return datos
        End Function

    Me tira el siguiente error:

    Se produjo una excepción de tipo 'System.InvalidCastException' en Microsoft.VisualBasic.dll pero no se controló en el código del usuario
    
    Información adicional: La conversión del tipo 'Conceptos' en el tipo 'Integer' no es válida.

    Gracias.

    sábado, 27 de agosto de 2016 8:06
  • Hola The High Road,

    Te recomendaría el uso del evento SelectionChangeCommitted del ComboBox en vez del SelectedIndexChanged.

    [-] ... Code

    Public Function VerDetalle(ByVal id As Integer) As Proveedores
            Dim cmd As New SqlCommand
            cmd.Parameters.AddWithValue("@IdCuenta", id)
    ....


    No entiendo la necesidad de retornar un valor de tipo Proveedores, si sólo vas a mandar un solo dato. Además deberías usar el ExecuteScalar ya que sólo obtienes un dato. Además el orden como declaras los valores en el método no es el adecuado.

    Ojo : El error que muestras talvéz se deba a que envías un parámetro erróneo. Mira los nombres :

    En la consulta solicitas una variable @IdConcepto pero le envías un @IdCuenta.

    Public Function VerDetalle(ByVal id As Integer) As Proveedores
            Using con As New SqlConnection(CadenaConexion)
                con.Open()
    
                Dim sql As String = "SELECT Detalle FROM Cuentas WHERE IdConcepto = @IdConcepto"
                Dim cmd As New SqlCommand(sql, con)
                cmd.Parameters.AddWithValue("@IdCuenta", id)
    
                Dim datos As New Proveedores
                datos.Detalle = CStr(cmd.ExecuteScalar())
    
                Return datos
            End Using
        End Function

    Saludos.


    JC NaupaCrispín
    Lima - Perú

    La magia no existe, la programación SI

    • Marcado como respuesta The High Road domingo, 28 de agosto de 2016 8:49
    sábado, 27 de agosto de 2016 14:05
  • The High Road,

    A ver, déjame hacerte llegar algunas consideraciones respecto al código mostrado:

    Primero, atiende la sugerencia de usar el evento SelectionChangeCommit en vez del evento SelectedIndexChanged cuando busques accionar código sólo cuando el usuario selecciona un elemento del desplegable, el evento SelectedIndexChanged se lanza incluso cuando el índice del elemento cambia mediante código, lo que podría acarrear resultados no esperados.

    Segundo, en la capa de UI veo que declaras la variable Proveedor de tipo Proveedores pero no veo que la instancies. Si no instancias la variable 'Proveedor' no podrás tener un objeto de tipo Proveedores y menos acceder a sus miembros.

    Dim Proveedor As New Proveedores

    Tercero,  noto que la capa de lógica de negocios implementa en la firma el modificador Friend, sin embargo la capa de acceso a datos implementa clases de instancia, ¿hay alguna explicación al respecto? Pienso que la capa de acceso a datos también debería implementar clases con el modificador Friend o ambas capas implementar clases de instancia y no porque sea una buena práctica sino porque no tiene sentido que una capa defina clases de instancia y la otra no, salvo que exista alguna explicación.

    Cuarto, en la capa de acceso a datos, el procedimiento de tipo Function llamado VerDetalle() retorna un tipo Proveedores, la consulta de selección filtra por el valor del parámetro @IdConcepto sin embargo tu cargas al objeto Command un valor para el parámetro @IdCuenta que no existe en el contexto de la consulta, ¿está mal definido el filtro en la consulta sql?, ¿está mal definido el nombre del parámetro que agregas al objeto Command?.

    Quinto, sobre el punto anterior, ¿el tipo Proveedores sólo tiene un miembro (propiedad Detalle)? Entiendo que debería tener más propiedades y todas ellas -salvo tengan el atributo NULLABLE- deberían establecer su valor a partir del objeto DataReader, caso contrario bastaría con recuperar el valor mediante el método ExecuteScalar(), sin embargo tengo mis dudas.

    Sexto, respecto al error, ¿donde es que interviene el tipo Conceptos?, ¿puedes detectar en que línea es que ocurre la excepción?


    Espero que la información proporcionada te haya sido de utilidad, quedo atento a tus comentarios.
    • Marcado como respuesta The High Road domingo, 28 de agosto de 2016 8:49
    sábado, 27 de agosto de 2016 16:33
  • Hola Joel C. Naupa Crispín y Willams Morales gracias por responder, y sí estaba mal la consulta SQL, hice un copy-paste y me olvide de cambiar el nombre de la variable. De todas formas una vez corregido esto me tiraba el mismo error.

    El problema real parece que era el evento SelectedIndexChanged como ambos mencionaron, lo cambie por SelectionChangeCommitted y además instancie la variable Proveedor y todo funcionó de maravillas!!!

    Además seguí sus recomendaciones usando el método ExecuteScalar().

    Estoy muy agradecido!!! Gracias por tomarse el tiempo de ayudarme y colaborar.

    You guys rock!!!


    domingo, 28 de agosto de 2016 8:57