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