ComboBox en un DataGrid Fecha: 18/Nov/2004 (10/11/2004)
|
. |
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 Class3) 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