ComboBox en un DataGrid
(La DataGrid Recargada)

Como crear una ComboBox Enlazada en un datagrid

Fecha: 18/Nov/2004 (10/11/2004)
Autor: Alvaro Regalado. alvaritus@msn.com

 

.

A pedido del público (se ve que les gustó el anterior :P ) les mando la parte II del artículo que anteriormente publiqué acerca de como insertar una Combo en un Datagrid. Ésta vez, veremos como se hace para crear una Combo enlazada a datos.

1) Bueno, lo primero que tenemos que hacer es Crear una clase que herede de DataGridTextBoxColumn, a la que llamaré DataGridComboBoxColumn. Ahí les va el código:

Imports Microsoft.VisualBasic
Imports System
Imports System.ComponentModel
Imports System.Data
Imports System.Data.Common
Imports System.Data.OleDb
Imports System.Drawing
Imports System.Windows.Forms

'Paso 1. Derivar un estilo de columna a DataGridTextBoxColumn
' a) agregar un miembro a la ComboBox 
' b) Detectar cuando la combobox tiene el foco en los eventos Enter y Leave
' c) Sobreescribir el Edit para permitir a la ComboBox remplazar la textbox de la Datagrid
' d) Sobreescribir el Commit para salvar los cambios de los datos

Public Class DataGridComboBoxColumn
    Inherits DataGridTextBoxColumn
    Public ColumnComboBox As ComboSinKeyUp 'Atención aquí con esta declaración
    Private _Origen As System.Windows.Forms.CurrencyManager
    Private _NroRenglon As Integer
    Private _EstaEditando As Boolean
    Public Shared _RowCount As Integer

    Public Sub New()
        _Origen = Nothing
        _EstaEditando = False
        _RowCount = -1

        ColumnComboBox = New ComboSinKeyUp
        ColumnComboBox.DropDownStyle = ComboBoxStyle.DropDownList

        AddHandler ColumnComboBox.Leave, AddressOf DejaComboBox
        AddHandler ColumnComboBox.SelectionChangeCommitted, AddressOf ComienzaEditarCombo
    End Sub

    Private Sub ManejaScroll(ByVal sender As Object, ByVal e As EventArgs)
        If ColumnComboBox.Visible Then
            ColumnComboBox.Hide()
        End If
    End Sub

    Private Sub ComienzaEditarCombo(ByVal sender As Object, ByVal e As EventArgs)
        _EstaEditando = True
        MyBase.ColumnStartedEditing(sender)
    End Sub

    Private Sub DejaComboBox(ByVal sender As Object, ByVal e As EventArgs)
        If _EstaEditando Then
            SetColumnValueAtRow(_Origen, _NroRenglon, ColumnComboBox.Text)
                _EstaEditando = False
                Invalidate()

            End If
            ColumnComboBox.Hide()
            AddHandler Me.DataGridTableStyle.DataGrid.Scroll, New EventHandler(AddressOf ManejaScroll)
        End Sub

        Protected Overloads Overrides Sub Edit(ByVal [source] As System.Windows.Forms.CurrencyManager, ByVal rowNum As Integer, ByVal bounds As System.Drawing.Rectangle, ByVal [readOnly] As Boolean, ByVal instantText As String, ByVal cellIsVisible As Boolean)

            MyBase.Edit([source], rowNum, bounds, [readOnly], instantText, cellIsVisible)

            _NroRenglon = rowNum
            _Origen = [source]

            ColumnComboBox.Parent = Me.TextBox.Parent
            ColumnComboBox.Location = Me.TextBox.Location
            ColumnComboBox.Size = New Size(Me.TextBox.Size.Width, ColumnComboBox.Size.Height)
            ColumnComboBox.SelectedIndex = ColumnComboBox.FindStringExact(Me.TextBox.Text)
            ColumnComboBox.Text = Me.TextBox.Text
            Me.TextBox.Visible = False
            ColumnComboBox.Visible = True
            AddHandler Me.DataGridTableStyle.DataGrid.Scroll, AddressOf ManejaScroll

            ColumnComboBox.BringToFront()
            ColumnComboBox.Focus()
        End Sub


        Protected Overrides Function Commit(ByVal dataSource As System.Windows.Forms.CurrencyManager, ByVal rowNum As Integer) As Boolean

            If _EstaEditando Then
                _EstaEditando = False
                SetColumnValueAtRow(dataSource, rowNum, ColumnComboBox.Text)
                End If
                Return True
            End Function

            Protected Overrides Sub ConcedeFocus()
                MyBase.ConcedeFocus()
            End Sub

            Protected Overrides Function GetColumnValueAtRow(ByVal [source] As System.Windows.Forms.CurrencyManager, ByVal rowNum As Integer) As Object

                Dim s As Object = MyBase.GetColumnValueAtRow([source], rowNum)
                Dim dv As DataView = CType(Me.ColumnComboBox.DataSource, DataView)
                Dim rowCount As Integer = dv.Count
                Dim i As Integer = 0
                Dim s1 As Object

                While i < rowCount
                    s1 = dv(i)(Me.ColumnComboBox.ValueMember)
                    If (Not s1 Is DBNull.Value) AndAlso _
                    (Not s Is DBNull.Value) AndAlso _
                    s = s1 Then
                    Exit While
                End If
                i = i + 1
            End While

            If i < rowCount Then
                Return dv(i)(Me.ColumnComboBox.DisplayMember)
            End If
            Return DBNull.Value
        End Function

        Protected Overrides Sub SetColumnValueAtRow(ByVal [source] As System.Windows.Forms.CurrencyManager, ByVal rowNum As Integer, ByVal value As Object)
            Dim s As Object = value

            Dim dv As DataView = CType(Me.ColumnComboBox.DataSource, DataView)
            Dim rowCount As Integer = dv.Count
            Dim i As Integer = 0
            Dim s1 As Object

            While i < rowCount
                s1 = dv(i)(Me.ColumnComboBox.DisplayMember)
                If (Not s1 Is DBNull.Value) AndAlso _
                s = s1 Then
                Exit While
            End If
            i = i + 1
        End While
        If i < rowCount Then
            s = dv(i)(Me.ColumnComboBox.ValueMember)
        Else
            s = DBNull.Value
        End If
        MyBase.SetColumnValueAtRow([source], rowNum, s)
    End Sub
End Class

 

2) Aquí va otra Clase llamada ComboSinKeyUp que hereda del control ComboBox. Lo que hace es ignorar el KeyUp en dicho control...

 

Public Class ComboSinKeyUp
    Inherits ComboBox
    Private WM_KEYUP As Integer = &H101

    Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
        If m.Msg = WM_KEYUP Then
            'Ignora el keyup para evita problemas de tabulación
            Return
        End If
        MyBase.WndProc(m)
    End Sub
End Class

3) Finalmente en la Form en la que tengo el Datagrid debo aplicarle un TableStyle determinado y dentro del mismo va a estar el tipo que hemos creado en la clase detalla anteriormente. A continuación va el código para crear el DataSet Y enlazar la Grid ( la columna 1 es del tipo DataGridComboBoxColumn.)

 

Private Sub HacerDataSetYEnlazarGrid()
    Private dataGrid1 As System.Windows.Forms.DataGrid
    Private miDataSet As DataSet
    Private dataAdapter As OleDbDataAdapter

    Dim connString As String = "Provider=Microsoft.JET.OLEDB.4.0;data source=C:\nwind.mdb"
    Dim sqlString As String = "SELECT * FROM Pedidos"
    dataAdapter = Nothing
    miDataSet = Nothing
    Try
        Dim connection As New OleDbConnection(connString)
        dataAdapter = New OleDbDataAdapter(sqlString, connection)
        miDataSet = New DataSet
        dataAdapter.Fill(miDataSet, "Pedidos")
        sqlString = "SELECT IDcliente, NombreContacto FROM Clientes"
        dataAdapter = New OleDbDataAdapter(sqlString, connection)
        dataAdapter.Fill(miDataSet, "Lista de Clientes")
        connection.Close()
    Catch ex As Exception
        MessageBox.Show(("Problema al acceder a la Base de datos" + ex.ToString()))
        Me.Close()
        Return
    End Try

    Dim tableStyle As New DataGridTableStyle
    tableStyle.MappingName = "Pedidos"

    Dim dt As DataTable = miDataSet.Tables("Pedidos")

    Dim i As Integer

    While i < dt.Columns.Count
        If i <> 1 Then
            Dim TextCol As New DataGridTextBoxColumn
            TextCol.MappingName = dt.Columns(i).ColumnName
            TextCol.HeaderText = dt.Columns(i).ColumnName
            tableStyle.GridColumnStyles.Add(TextCol)
        Else
            Dim ComboTextCol As New DataGridComboBoxColumn
            ComboTextCol.MappingName = "IDCliente"
            ComboTextCol.HeaderText = "Cliente (Combo)"
            ComboTextCol.Width = 120
            ComboTextCol.ColumnComboBox.DataSource = miDataSet.Tables("Lista de Clientes").DefaultView 
            ComboTextCol.ColumnComboBox.DisplayMember = "NombreContacto"
            ComboTextCol.ColumnComboBox.ValueMember = "IDCliente"

            tableStyle.PreferredRowHeight = ComboTextCol.ColumnComboBox.Height + 2

            tableStyle.GridColumnStyles.Add(ComboTextCol)
        End If
        i = i + 1
    End While

    dataGrid1.TableStyles.Clear()
    dataGrid1.TableStyles.Add(tableStyle)
    dataGrid1.DataSource = dt


End Sub

 


ir al índice