Llenar un ComboBox IV

Última entrega. Por fin lo útil: llenar el Combo, el ListBox y alguna cosita más.

El corazón de la clase son dos métodos privados que son los que rellenan el ListControl (ya sea un ListBox o un ComboBox). Ambos reciben como parámetros el control que se va a rellenar, el nombre de la tabla origen, los dos campos con los que vamos a rellenar el control (indentificados por su índice en la colección de columnas de la tabla, o su posición, para entendernos), una sentencia WHERE para ajustar la consulta y una sentencia de ordenación, ambas sin las palabras reservadas WHERE y ORDER BY. El método para OleDB es el siguiente:

Private Function RellenarComboOleDB( _
        ByVal MiControl As System.Windows.Forms.ListControl, _
        ByVal Tabla As String, ByVal ClavePrincipal As Integer, _
        ByVal CampoDescriptor As Integer, _
        ByVal SentenciaWhere As String, _
        ByVal SentenciaOrderBy As String) As Boolean
    Dim drDatos As OleDb.OleDbDataReader
    Dim Comando As New OleDb.OleDbCommand("SELECT * FROM " & Tabla, _
                                    Me._cnOleDb)
    Dim tbTabla As New DataTable
    Dim deVuelta As Boolean
    Try
        If SentenciaWhere.Length > 0 Then
            Comando.CommandText = "SELECT * FROM " & Tabla _
                    & " WHERE " & SentenciaWhere
        End If
        If SentenciaOrderBy.Length > 0 Then
            Comando.CommandText = Comando.CommandText & _
                    " ORDER BY " & SentenciaOrderBy
        End If
        drDatos = Comando.ExecuteReader()
        tbTabla.Load(drDatos, LoadOption.OverwriteChanges)
        MiControl.DataSource = tbTabla
        MiControl.DisplayMember = _
            tbTabla.Columns.Item(CampoDescriptor).Caption
        MiControl.ValueMember = _
            tbTabla.Columns.Item(ClavePrincipal).Caption
        drDatos.Close()
        deVuelta = True
    Catch NoConexion As InvalidOperationException
        'Error del Comado.ExecuteReader
        deVuelta = False
        Throw NoConexion
    Catch NoConexion As Exception
        deVuelta = False
        Throw NoConexion
    Finally
        Comando = Nothing
        tbTabla = Nothing
    End Try
    Return deVuelta
End Function

Para SQL es similar, pues sólo cambian el nombre (RellenarComboSQL), el tipo de objeto DataReader, el Command y la conexión utilizada, es decir, en vez de:

Dim drDatos As OleDb.OleDbDataReader
Dim Comando As New OleDb.OleDbCommand("SELECT * FROM " & Tabla, _
        Me._cnOleDb)

Tendríamos:

Dim drDatos As SqlClient.SqlDataReader
Dim Comando As New SqlClient.SqlCommand("SELECT * FROM " & Tabla, _
        Me._cnSQL)

Como métodos públicos tenemos dos variantes, donde jugamos con la sobrecarga de operadores. El primero, que se muestra a continuación, es el principal. En él asumimos que la conexión ya está abierta, bien porque hemos llamado previamente al método Conectar, bien porque le hemos pasado un objeto conexión a través de la propiedad ConexionOleDB o ConexionSQL. Como puede verse, los parámetros que recibe son los mismos que reciben los métodos privados vistos antes, con la salvedad de que, salvo el control y el nombre de la tabla, los demás son opcionales. En lo que a mí respecta, la situación más habitual para la que estoy usando esta clase es para rellenar combos con tablas que no tienen más de 10-15 registros y tres campos: por orden, IdTabla, Nombre y Descripción, siendo los dos primeros los campos a mostrar en el combo. De ahí los valores por defecto de los parámetros opcionales.

Lo que hace el método es identificar con qué base de datos estamos tratando y llamar al método privado correspondiente, pasándole por parámetro lo que a él le ha llegado.

''' <summary>
''' Rellena un ListControl con un campo descriptor 
''' y la clave principal de una tabla
''' para usarlo como clave externa en otra tabla.
''' </summary>
''' <param name="MiControl">ListControl (Combo, ListBox)
''' que se va a rellenar</param>
''' <param name="Tabla">Nombre de la tabla a rellenar</param>
''' <param name="ClavePrincipal">Número del campo Clave Principal
''' en la tabla (por defecto, 0)</param>
''' <param name="CampoDescriptor">Número del campo descriptor
''' usado como DisplayMember del Combo (por defecto, el 1)</param>
''' <param name="SentenciaWhere">Sentencia WHERE de la selección
''' SQL (sin el WHERE). Puede incluir más opciones, como ORDER BY.
''' No se realiza ninguna comprobación sobre la sentencia</param>
''' <param name="OrdenarPor">Sentencia ORDER BY, si la hay.</param>
''' <returns>True operación completada, False si se ha producido
''' un error</returns>
''' <remarks>Hay que haber pasado previamente la cadena de
''' conexión a la propiedad CadConexion y abrir la conexión
''' con el método Conectar antes de llamar a este método
''' y llamar a Desconectar al finalizar.</remarks>
Public Function RellenarCombo(ByVal MiControl As _
        System.Windows.Forms.ListControl, _
        ByVal Tabla As String, _
        Optional ByVal ClavePrincipal As Integer = 0, _
        Optional ByVal CampoDescriptor As Integer = 1, _
        Optional ByVal SentenciaWhere As String = "", _
        Optional ByVal OrdenarPor As String = "") As Boolean
    Dim deVuelta As Boolean
    'Según el tipo de base de datos al que estemos conectados, 
    'llama a una u otra función que rellenarán el combo.
    Try
        Select Case _BDD
            Case QueBase.Access
                deVuelta = Me.RellenarComboOleDB(MiControl, _
                    Tabla, ClavePrincipal, CampoDescriptor, _
                    SentenciaWhere, OrdenarPor)
            Case QueBase.SQL
                deVuelta = Me.RellenarComboSQL(MiControl, _
                    Tabla, ClavePrincipal, CampoDescriptor, _
                    SentenciaWhere, OrdenarPor)
            Case Else
                deVuelta = False
                Throw New ApplicationException( _
                    "Tipo de base de datos desconocido o no establecido")
        End Select
    Catch NoConexion As Exception
        Throw NoConexion
        deVuelta = False
    End Try
    Return deVuelta
End Function

La otra variante de RellenarCombo no necesita tener una conexión abierta, sino que se preocupa él mismo de abrirla y cerrarla. Para ello, tiene un parámetro adicional que es la cadena de conexión. Así, si sólo vamos a llenar un ListControl, podemos usar este método y condensarlo todo en una única llamada, mientras que usaremos el anterior si vamos a aprovechar la conexión abierta para más cosas (llenar varios combos y listboxes, llenar algún dataset…).

Public Function RellenarCombo(ByVal MiControl As _
        System.Windows.Forms.ListControl, _
        ByVal Tabla As String, _
        ByVal CadenaConexion As String, _
        Optional ByVal ClavePrincipal As Integer = 0, _
        Optional ByVal CampoDescriptor As Integer = 1, _
        Optional ByVal SentenciaWhere As String = "", _
        Optional ByVal OrdenarPor As String = "") As Boolean
    Dim DeVuelta As Boolean
    Try
        Me.CadConexion = CadenaConexion
        DeVuelta = Me.Conectar
        If DeVuelta Then
            DeVuelta = Me.RellenarCombo(MiControl, _
                Tabla, ClavePrincipal, CampoDescriptor, _
                SentenciaWhere, OrdenarPor)
        End If
    Catch NoConexion As Exception
        DeVuelta = False
        Throw NoConexion
    Finally
        Me.Desconectar()
    End Try
    Return DeVuelta
End Function

Y eso es todo. No es ninguna maravilla, pero me es útil. Si a alguien le sirve, pues mejor.

*Ejem* Bueno, no es todo. RellenarCombo presenta 4 sobrecargas (variantes) y aquí sólo he puesto dos de ellas. Las otras dos son iguales, pero cambiando el ListControl por un DataGridViewComboBoxColumn, o sea, la variante del ComboBox para DataGridView. Cambiando ese pequeño detalle, son exactamente iguales y, por supuesto, llevan sus métodos privados correspondientes (RellenarComboDataGridOleDB y RellenarComboDataGridSQL, de momento). Y, ahora, sí, eso es to… to… todo, amigos.

Deja un comentario