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. [email protected]

 

.

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