lunes, 15 de marzo de 2010

DataGridView desplegable

Ejemplo en vb.net para desplegar un control DataGridView mediante un combobox con estilo DropDownList

Nota: Al ejemplo se le podrian agregar muchas mas opciones de las que tiene ( que no son muchas). y está pensado mas que nada para usarlo en una grilla que solo visualice datos y poder desplegar la lista y seleccionar un valor, ya que el formulario que contiene el DataGridView, no tiene implementadas opciones para eliminar filas, agregar etc., ( es algo bien simple ) , solo tiene un botón para cerrar la lista y poder asignar y mostrar la fila actual en el combo

Descripción

Para enlazar el datagridView al comboBox, se debe crear una instancia de una clase que tiene un método llamado Iniciar, y luego enviarle como parámetro a esa función , los dos controles: El DataGridview a usar y el control combobox
Para indicar la columna del datagridview que se visualizará en el control combo al cerrar la lista o al moverse por las filas de la grilla, se debe indicar el índice al la propiedad ColumnDefault y tiene algunas otras propiedades para cambiar el ancho y alto del listado, si la lista se muetra como un diálogo modal o normal, y si se visualizará un tooltiptext para el combo


Código fuente

En un formulario con los siguientes controles :
  • dos controles dataGridView : llamados dataGridview1 y dataGridview2
  • Dos controles Combobox : ComboBox1 y Combobox2

Código fuente
Option Explicit On
Option Strict On

Public Class Form1

Private WithEvents mClass1 As Class1
Private WithEvents mClass2 As Class1

Private Sub Form1_FormClosed(ByVal sender As Object, _
ByVal e As System.Windows.Forms.FormClosedEventArgs) Handles Me.FormClosed

If Not mClass1 Is Nothing And mClass2 Is Nothing Then
mClass1.Dispose()
mClass2.Dispose()

mClass1 = Nothing
mClass2 = Nothing
End If

End Sub

Private Sub Form1_Load(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Load

' agregar algunos datos al datagridview 1
With DataGridView1
.Columns.Add("id", "Id")
.Columns.Add("Producto", "Producto")
.Columns.Add("Precio", "Precio")
.Columns.Add("stock", "Stock actual")
.Columns.Add("Proveedor", "Contacto Proveedor")

.RowCount = 100

For i As Integer = 0 To .RowCount - 1
.Item(0, i).Value = i.ToString
.Item(1, i).Value = "Producto " & i.ToString
.Item(2, i).Value = Format(225 + i, "c")
.Item(3, i).Value = CInt(Rnd() * 100)
.Item(4, i).Value = "Proveedor: " & i.ToString
Next
End With

' DataGridView 2

'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

With DataGridView2
.Columns.Add("id Cliente", "id Cliente")
.Columns.Add("Nombre", "Nombre")
.Columns.Add("Apellido", "Apellido")

.RowCount = 100

For i As Integer = 0 To .RowCount - 1
.Item(0, i).Value = i.ToString
.Item(1, i).Value = "Nombre " & i.ToString
.Item(2, i).Value = "Apellido" & i.ToString

Next

End With


' 1 - nueva instancia
mClass1 = New Class1

' configurar
With mClass1
' indicar el combo y el datagridview
.Iniciar(ComboBox1, DataGridView1)

.AltoLista = 400 ' alto
.ColumnaDefault = 1 ' columna que se va a mostrar
.ShowToolTip = True ' mostrar o no el toolTiptext
.ShowDialog = False ' modal o normal

End With



' 2 --
'''''''''''''''''''''''''
mClass2 = New Class1

With mClass2
.Iniciar(ComboBox2, DataGridView2)
.AltoLista = 120
.AnchoLista = 350
.ColumnaDefault = 0
.ShowDialog = True

.ShowToolTip = True
End With

ComboBox1.Items.Add(DataGridView1.Item(1, 0).Value.ToString)
ComboBox1.SelectedIndex = 0

ComboBox2.Items.Add(DataGridView1.Item(0, 0).Value.ToString)
ComboBox2.SelectedIndex = 0

End Sub

Private Sub mClass1_ButtonClose() Handles mClass1.onButtonClose
mClass1.closeList()
End Sub
Private Sub mClass2_ButtonClose() Handles mClass2.onButtonClose
mClass2.closeList()
End Sub

End Class

Código de la clase llamada Class1
Option Explicit On
Option Strict On

Public Class Class1

' función PostMessage para cancelar el DropDown
Private Const CB_SHOWDROPDOWN As Integer = &H14F
Private Declare Function PostMessage Lib "user32" _
Alias "PostMessageA" (ByVal hwnd As IntPtr, _
ByVal wMsg As Integer, ByVal wParam As Integer, _
ByVal lParam As Integer) As Integer

' Variables para los controles
Private WithEvents m_ComboBox As ComboBox
Private WithEvents m_DataGridView As DataGridView
Private WithEvents m_frm_Container As Form
Private WithEvents m_ButtonClose As Button

' variables
Private m_Ancho_Lista As Integer = 500
Private m_Alto_Lista As Integer = 130
Private m_Columna As Integer = 0
Private mShowToolTip As Boolean = False
Private mShowDialog As Boolean = False

Private tooltip As ToolTip

' eventos
Public Event onButtonClose()
Public Event onCloseList()
Public Event onOpenList()


' Propiedades
'
''' <summary>
''' Establece la Columna del DataGridView a mostrar en el combobox
''' </summary>
Public Property ColumnaDefault() As Integer

Get
Return m_Columna
End Get

Set(ByVal value As Integer)
m_Columna = value
End Set

End Property

''' <summary>
''' Establecer el alto de la lista desplegable
''' </summary>
Public Property AltoLista() As Integer
Get
Return m_Alto_Lista
End Get
Set(ByVal value As Integer)
If value < 100 Then
m_Alto_Lista = 200
Else
m_Alto_Lista = value
End If
End Set
End Property

''' <summary>
''' Establecer el Ancho de la lista desplegable
''' </summary>
'''
Public Property AnchoLista() As Integer
Get
Return m_Ancho_Lista
End Get
Set(ByVal value As Integer)
' si el ancho es menor al width del combo ...
If value <= m_ComboBox.Width Then
'.. asignar el mismo ancho
m_Ancho_Lista = m_ComboBox.Width + 10
Else
m_Ancho_Lista = value
End If

End Set
End Property
''' <summary>
''' ' Mostrar o no mostrar el objeto ToolTip para el ComboBox
''' </summary>

Public Property ShowToolTip() As Boolean
Get
Return mShowToolTip
End Get
Set(ByVal value As Boolean)
mShowToolTip = value
End Set
End Property

''' <summary>
''' ' Mostrar la lista desplegable como Modal o Normal
''' </summary>
Public Property ShowDialog() As Boolean
Get
Return mShowDialog
End Get
Set(ByVal value As Boolean)
mShowDialog = value
End Set
End Property

''' <summary>
''' ' ' Iniciar la instancia
''' </summary>

Sub Iniciar(ByVal Combo As ComboBox, _
ByVal DataGridView As DataGridView)

If Not (m_ComboBox Is Nothing) Or Not (m_DataGridView) Is Nothing Then
MsgBox("Ya se han indicado los controles")
Exit Sub
End If

' Configurar el combobox
m_ComboBox = Combo
With m_ComboBox
.DropDownHeight = 1
.DropDownWidth = 1
.DropDownStyle = ComboBoxStyle.DropDownList
.Items.Clear()
End With

' Configurar el formulario contenedor
m_frm_Container = New Form
With m_frm_Container
.FormBorderStyle = FormBorderStyle.None ' form sin borde
.ShowInTaskbar = False ' Ocultarlo del Taskbar
.Visible = False
End With

' Configurar el dataGridView
m_DataGridView = DataGridView
With m_DataGridView
.Parent = m_frm_Container ' asignar el contenedor del DataGridView
.Visible = True
' Para seleccionar la fila completa
.SelectionMode = DataGridViewSelectionMode.FullRowSelect
End With

' botón para cerrar la lista
m_ButtonClose = New Button
With m_ButtonClose
' Asignar el formulario que lo contiene
.Parent = m_frm_Container
End With

End Sub

Private Sub m_ComboBox_GotFocus(ByVal sender As Object, _
ByVal e As System.EventArgs) Handles m_ComboBox.GotFocus
With m_ComboBox
.BackColor = Color.White
.ForeColor = Color.Black

End With
End Sub

' Abir la lista desplegable al presionar Enter
Private Sub m_ComboBox_KeyDown(ByVal sender As Object, _
ByVal e As System.Windows.Forms.KeyEventArgs) Handles m_ComboBox.KeyDown
If (e.KeyCode = Keys.Enter) And(m_ComboBox.Focused) And _
(m_frm_Container.Visible = False) Then

showList()
End If
End Sub



' Cancelar el DropDown con PostMessage, y mostrar o cerrar la lista
Private Sub m_ComboBox_MouseDown(ByVal sender As Object, _
ByVal e As System.Windows.Forms.MouseEventArgs) _
Handles m_ComboBox.MouseDown

PostMessage(m_ComboBox.Handle, CB_SHOWDROPDOWN, 0, 0)

showList()
End Sub

''' <summary>
''' Evento para cerrar la lista desplegable
''' </summary>
Sub closeList()
' Establecer los datos para la info sobre herramientas
MostrarToolTip()
RaiseEvent onCloseList() ' Lanzar evento
' ocultar el formulario
If m_frm_Container.Visible Then
m_frm_Container.Visible = False
With m_ComboBox
.Focus()
End With
End If
End Sub

' al desactivarse el formulario que hace de lista, ocultarlo

Private Sub m_frm_Container_Deactivate(ByVal sender As Object, _
ByVal e As System.EventArgs) Handles m_frm_Container.Deactivate
If m_frm_Container.Visible Then m_frm_Container.Visible = False

End Sub

''' <summary>
''' Evento para Abrir la lista desplegable
''' </summary>
Sub showList()

' si el form de lista está visible sale
If m_frm_Container.Visible Then Exit Sub

' obtener la posición Left y Top del combo en la pantalla
Dim Posicion As System.Drawing.Point
Dim point_CBox As Point = m_ComboBox.PointToScreen(Posicion)
Dim new_point_combo As Point = m_frm_Container.PointToClient(point_CBox)

' posicionar el formulario en la posición del combo
With m_frm_Container
.SetBounds((point_CBox.X),(point_CBox.Y + m_ComboBox.Height), _
(m_Ancho_Lista),(m_Alto_Lista + 25))

.BringToFront() ' traerlo al frente
End With

' propiedaedes para el comboBox
With m_ComboBox
.BackColor = Color.AliceBlue
.ForeColor = Color.Black
End With

' Propiedades del botón
With m_ButtonClose

.Text = "Cerrar"

' para obtener el ancho del texto del botón con MeasureString
Dim g As Graphics = m_frm_Container.CreateGraphics
Dim WFont As New System.Drawing.SizeF

WFont = g.MeasureString(.Text, .Font)
g.Dispose()

' asignar el tamaño y la posición del button
.Size = New Size(CInt(WFont.Width * 1.21), 22)
.Location = New Point(m_frm_Container.Width - (.Width + 2), _
m_frm_Container.Height - (.Height) - 2)


End With

' Configurar el DataGridView ( el tamaño, la posición, establecerle el foco)
With m_DataGridView

If .Parent Is Nothing Then
.Parent = m_frm_Container
End If

.SetBounds(2, 3, (.Parent.Width - 5), (.Parent.Height - 34))
End With
' lanzar evento
RaiseEvent onOpenList()

' hacer visible la lista desplegable ( modal o normal )
If mShowDialog Then ' modal
m_DataGridView.Focus()
m_frm_Container.ShowDialog()
m_ComboBox.Focus()
Else
m_frm_Container.Show() ' normal
m_DataGridView.Focus()
End If
End Sub

' lanzar evento
Private Sub m_button_Close_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles m_ButtonClose.Click
RaiseEvent onButtonClose()
End Sub

Private Sub m_DataGridView_CellEndEdit(ByVal sender As Object, _
ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) _
Handles m_DataGridView.CellEndEdit

' Al editar la celda actualizar el texto del Combobox
If e.ColumnIndex = m_Columna Then
With m_ComboBox
.Items.Clear()
.Items.Add(ValueColumn)
.Text = ValueColumn()
End With
End If
End Sub

Private Sub m_DataGridView_KeyDown(ByVal sender As Object, _
ByVal e As System.Windows.Forms.KeyEventArgs) Handles m_DataGridView.KeyDown
'si se presiona la tecla escape, cerrar la lista
If (e.KeyCode = Keys.Escape) Then
closeList()
End If
End Sub

' Cambiar el valor del combo al cambiar el valor seleccionado del DataGridView
Private Sub m_DataGridView_SelectionChanged(ByVal sender As Object, _
ByVal e As System.EventArgs)Handles m_DataGridView.SelectionChanged

With m_ComboBox
.Items.Clear()
Dim valor As Object = ValueColumn()

If Not valor Is Nothing Then
.Items.Add(ValueColumn)
.Text = ValueColumn()
End If
End With
End Sub


''' <summary>
''' función que retorna el valor de la celda de la columna default
''' </summary>
Function ValueColumn() As String

If m_DataGridView Is Nothing Or m_DataGridView.CurrentRow Is Nothing Then
Return Nothing
Else
With m_DataGridView
Try
If Not .Item(m_Columna, _
.CurrentRow.Index).Value Is Nothing Then

Return m_DataGridView.Item(m_Columna,.CurrentRow.Index).Value.ToString


End If
Catch ex As Exception
MsgBox(ex.Message.ToString)
End Try
End With
End If
Return Nothing
End Function

' Rutina que recorre las columnas de la fila del datagridView para _
' obtener el texto y asignarlo al objeto toolTip para el combobox
Private Sub MostrarToolTip(Optional ByVal delay As Integer = 3000)

' si la fila actual es Nothing o mShowToolTip es Falso ..salir
If (m_DataGridView.CurrentRow Is Nothing) Or (mShowToolTip = False) Then
Exit Sub
End If

Dim texto As String = String.Empty

With m_DataGridView
' recorrer las columnas
For i As Integer = 0 To .ColumnCount - 1
Dim Header_text As String = .Columns(i).HeaderText

' verificar que el valor no sea Nothing
If Not (.Item(i, .CurrentRow.Index).Value) Is Nothing Then
If .Item(i, .CurrentRow.Index).Value.ToString <> String.Empty Then

'Usar la colección Item para obtener el valor de la celda
Dim Celda As String = .Item(i, .CurrentRow.Index).Value.ToString
' guardar el caption del header + el texto de la celda
texto = texto &Header_text & ": " &Celda & vbCrLf
End If
End If

Next
End With

If Not tooltip Is Nothing Then tooltip.Dispose()

' nuevo tooltip
tooltip = New ToolTip

' configurarlo ( el delay, el tipo, el título y el texto anterior )
With tooltip
.AutomaticDelay = delay
.IsBalloon = True
.ToolTipIcon = ToolTipIcon.Info

.ToolTipTitle = m_DataGridView.Item(m_Columna, _
m_DataGridView.CurrentRow.Index).Value.ToString

.SetToolTip(m_ComboBox, texto)
End With
End Sub

' al repintar el formulario de lista, dibujar un rectángulo del
'tamaño del form con la función DrawRectangle
Private Sub m_frm_Container_Paint(ByVal sender As Object, _
ByVal e As System.Windows.Forms.PaintEventArgs) Handles m_frm_Container.Paint
'System.Drawing.SystemPens.GradientInactiveCaption()

e.Graphics.DrawRectangle(Pens.Silver,New Rectangle(0, 1, _
m_frm_Container.Width - 2, m_frm_Container.Height - 2))
End Sub

Sub Dispose()
Finalize()
End Sub

Protected Overrides Sub Finalize()
MyBase.Finalize()
Me.m_ComboBox = Nothing
Me.m_ButtonClose = Nothing
Me.m_DataGridView = Nothing
Me.m_frm_Container = Nothing
End Sub

End Class

No hay comentarios:

Publicar un comentario