Agenda telefónica 2 y control DataGrid

  • Conexión por Ado .NET con una base de datos de Access
  • Datos mostrados en control DataGrid personalizado
  • Filtros de búsqueda de registros por sentencias SQL
  • Creación de una clase propia de columna de DataGrid

En el ejercicio anterior "Agenda telefónica 2 en VBasic .NET" se realizó una aplicación que conecta con una base de datos de Microsoft Access y, mediante DataBinding (enlace de datos a los controles de un formulario), presenta los registros de uno en uno en un formulario, con unos botones de navegación entre registros y de edición de esos mismos registros (añadir nuevo, eliminar registro...). Pero en esta ocasión los datos se mostrarán en forma de tabla o cuadrícula de múltiples registros, con posibilidad de buscar con arreglo a determinados patrones de búsqueda.

Control DataGrid

En ADO .NET existe un control específico para mostrar los datos de una o varias tablas contenidas en un DataSet. Se trata del DataGrid que permite crear, de manera automática, un enlace complejo con los datos, ahorrando trabajo de escritura de código pues tiene implementadas muchas funciones útiles para mostrar y manipular campos de una o varias tablas.
El control DataGrid de los formularios Windows Forms muestra datos en una serie de filas y columnas. En el caso más sencillo, la cuadrícula está enlazada a un origen de datos con una sola tabla que no tiene relaciones. En ese caso, los datos aparecen en filas y columnas simples, como en una hoja de cálculo.
Si el control DataGrid está enlazado a datos con varias tablas relacionadas y está habilitado el desplazamiento en la cuadrícula, ésta mostrará controles de expansión en cada fila. Un control de expansión permite el desplazamiento desde una tabla primaria a una tabla secundaria. Al hacer clic en un nodo se muestra la tabla secundaria y al hacer clic en el botón Atrás se muestra la tabla primaria original. De este modo, la cuadrícula muestra las relaciones jerárquicas entre tablas.
El control DataGrid puede proporcionar una interfaz de usuario para un conjunto de datos, desplazamiento entre tablas relacionadas, así como formato enriquecido y posibilidades de edición.
La presentación y la manipulación de datos son funciones independientes: el control gestiona la interfaz de usuario, mientras que las actualizaciones de datos las administra la arquitectura de enlace a datos de los formularios Windows Forms y los proveedores de datos de .NET Framework.
Cuando la cuadrícula está enlazada a un objeto DataSet, se crean las columnas y las filas, se les da formato y se rellenan, todo automáticamente.

Para que funcione el control DataGrid, debe estar enlazado a un origen de datos por medio de las propiedades DataSource y DataMember. Este enlace hace que el control DataGrid señale a una instancia de un objeto de origen de datos (como DataSet o DataTable). Mediante el control DataGrid se muestran los resultados de las acciones que se ejecutan en los datos. La mayoría de las acciones específicas para datos no se ejecutan por medio del control DataGrid , sino a través del origen de datos.

El DataGrid es un control complejo, potente y flexible cuya apariencia y comportamiento por defecto, si bien son válidos para la finalidad perseguida, son fácilmente modificables tanto en modo de diseño como por código. Algunas de las numerosas propiedades de un DataGrid que podemos modificar son: BackColor, AlternatingBackColor, CaptionText, CaptionBackColor, CaptionForeColor, Alignment, HeaderText, etc.

Si no asignamos ningún valor a la propiedad DataMember del DataGrid y el DataSet tuviera más de una tabla, el propio DataGrid, gracias a la funcionalidad del mecanismo de DataBinding, ofrece la posibilidad de seleccionar la tabla origen de datos mediante un nodo expandible.

El control DataGrid puede utilizarse para mostrar una única tabla o las relaciones jerárquicas entre un conjunto de tablas. Cuando el control DataGrid muestra una tabla y la propiedad AllowSorting está establecida en true, es posible ordenar los datos de nuevo haciendo clic en los encabezados de columna. El usuario puede también agregar filas y modificar celdas.

Aparte de los eventos comunes de control tales como MouseDown, Enter y Scroll, el control DataGrid admite eventos asociados con la edición y el desplazamiento dentro de la cuadrícula. La propiedad CurrentCell determina cuál es la celda seleccionada. Cuando el usuario se desplaza a una nueva celda, se provoca el evento CurrentCellChanged. Cuando el usuario se desplaza a una nueva tabla (a través de relaciones primarias o secundarias), se produce el evento Navigate. El evento BackButtonClick se produce cuando el usuario hace clic en el botón Atrás mientras ve una tabla secundaria; el evento ShowParentDetailsButtonClick se produce cuando se hace clic en el icono para mostrar u ocultar filas primarias.

 

Filtrar registros del DataGrid

En el formulario de esta aplicación se han creado botones de comando correspondientes a las letras del alfabeto para filtrar los registros seleccionando solamente aquellos que empiezan por la letra elegida (equivale a las páginas de las agendas telefónicas). El mecanismo de filtrado es sencillo: se utiliza una sentencia SQL de selección que incluye el operador LIKE junto a la letra del botón pulsado (cada botón tiene su propiedad Text asignada a una letra del alfabeto), como si ejecutásemos (por ejemplo, al pulsar el botón A):

SELECT * FROM AgendaTb WHERE Nombre LIKE A%

El código que se ejecuta al pulsar en cualquiera de los botones con las distintas letras es éste:

        'filtrar registros por la letra inicial
       
Private Sub A_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles A.Click, _
        B.Click, C.Click, D.Click, E.Click, F.Click, G.Click, H.Click, I.Click, J.Click, K.Click, L.Click, M.Click, _
        N.Click, O.Click, P.Click, Q.Click, R.Click, S.Click, T.Click, U.Click, V.Click, Y.Click, Z.Click
           
'aplicar un filtro a la tabla Agenda del DataSet mediante un DataView
            'DataView permite personalizar las vistas de las tablas
            'Si la base de datos está abierta
           
If abierto = True Then
                Try
                    Dim vista As New DataView
                   
vista.Table = datos.Tables("Agendatb")
                    'filtro SQL: registros que empiecen por el texto escrito en el TextBox
                    vista.RowFilter = "Nombre LIKE '" & sender.Text & "%'"
                    'nuevo origen del DataDrid: la vista personalizada
                    Me.Grid.DataSource = vista
                    'recargar el DataGrid
                   
Me.Grid.Update()
                    Dim a As Integer
                    a = vista.Count
                   
'Dim aviso4 As String = a & " Registros recuperados  "
                   
'MessageBox.Show(aviso4, "Filtrado", MessageBoxButtons.OK)
                   
Me.Label2.Text = "Número de registros: " & a
               
Catch pollo As Exception
                    MessageBox.Show(pollo.Message.ToUpper, "Aviso al usuario", MessageBoxButtons.OK)
                End Try
                'Else
                '    Dim aviso4 As String = "Primero has de cargar la base de datos"
                '    MessageBox.Show(aviso4.ToUpper, "Aviso al usuario")
           
End If
        End
Sub
 

Además de ello se ha creado otro modo de filtrado escribiendo texto en una caja de texto por si se desea buscar según patrones de más de una letra.
 

DataGridTextBoxColumn personalizada (clase propia)

Para que las cajas de texto de los teléfonos acepten solamente números y no letras, se ha creado una clase DataGridTextboxColumnNumbers, derivada (herencia) de la clase DataGridTextboxColumn (perteneciente a la clase DataGrid). En la clase DataGridTextboxColumnNumbers se define un procedimiento que sólo deja pasar la tecla pulsada si se trata de un número:

        'Pocedimiento específico de configuración del cuadro de texto en cuanto a teclas pulsadas
       
Private Sub HandleKeyPress(ByVal sender As Object, ByVal e As KeyPressEventArgs)
           
Select Case e.KeyChar ' según el valor de la tecla pulsada
                ' pasan valores si la tecla pulsada es un número de 0 a 9
           
Case "1"c, "2"c, "3"c, "4"c, "5"c, "6"c, "7"c, "8"c, "9"c, "0"c
                   
e.Handled = False
                    ' si la propiedad Handled del objeto e se pone a True indico
                    ' que la tecla ha sido "manejada" por el evento, equivale a
                    ' indicar que la tecla no ha sido pulsada, pero si la propiedad
                    ' Handled del objeto e se pone a False indico que la tecla
                    ' todavía no ha sido "manejada" por el evento y se envía.
                Case Else ' en los demás casos, no se pasa la pulsación
                   
e.Handled = True
            End Select

        End Sub

Para disponer de este procedimiento, usamos una instrucción AddHandler en el método constructor de la clase. La instrucción AddHandler asocia un evento a un manipulador de eventos. Aquí asocia la pulsación de una tecla en el TextBox con el manipulador de su evento KeyPress y refiere al procedimiento descrito más arriba (HandleKeyPress):

'Espacio de nombre propio de la aplicación, al pertenecer a este espacio
'de nombres las 2 clases del ejercicio (Datagrid y DataGridDigitsTextBoxColumn)
'hay herencia entre ellas y podemos usar esta clase DataGridDigitsTextBoxColumn
'dentro de la otra clase DataGrid

Namespace
DataGridNumbersOnly
 
    'Clase DataGridTextBoxColumnNumbers que definiremos en este archivo,
   
'hereda de DataGridTextBoxColumn
    Public Class DataGridTextBoxColumnNumbers
       
Inherits DataGridTextBoxColumn
 
        'Método constructor de la clase
        Public Sub New()

            'MyBase se refiere a la clase madre DataGridTextBoxColumn, de la que hereda
            MyBase.New()

            'la instrucción AddHandler asocia un evento a un manipulador de eventos
            'aquí asocia la pulsación de una tecla en el TextBox con el manipulador
            'de su evento KeyPress y refiere al procedimiento HandleKeyPress
           
AddHandler Me.TextBox.KeyPress, New System.Windows.Forms.KeyPressEventHandler(AddressOf HandleKeyPress)
       
End Sub
 

Los mecanismos de herencia nos permiten disponer de la clase DataGridTextboxColumnNumbers en la clase principal del programa. Al personalizar el Datagrid, creamos una columna del tipo DataGridTextboxColumn (la clase proporcionada por la clase DataGrid, no filtra las pulsaciones de teclas, corresponde a la columna Nombre, en la que podemos necesitar esribir tanto letras como números) y otras 2 columnas del tipo DataGridTextboxColumnNumbers (la clase creada por nosotros mismos, corresponde a las 2 columnas de los teléfonos, solamente deja escribir números):

                        'crear un objeto para estilos en el Datagrid
                       
Dim estilo As New DataGridTableStyle
                        estilo.MappingName = "Agendatb"
                        estilo.BackColor = Color.White
                        estilo.AlternatingBackColor = Color.LightGray
 
                       
'Crear objetos del tipo DataGridTextBoxColumn
                        'para cada columna de la tabla del Datagrid
                        Dim columna As New DataGridTextBoxColumn
 
                        'Configurar cada columna
                        'Esta es la primera columna
                        columna = New DataGridTextBoxColumn
                       
columna.TextBox.MaxLength = 50
                        columna.Alignment = HorizontalAlignment.Left
                       
columna.HeaderText = "Nombre del contacto"
                        'columna del Dataset enlazada con esta columna del Datagrid
                        columna.MappingName = "Nombre"
                        columna.Width = 330
                        'texto que se muestra cuando la columna tiene valor null
                        columna.NullText = ""
                        'añadir la columna a los estilos del Datagrid
                        estilo.GridColumnStyles.Add(columna)

                        'CREACION DEL ESTILO PARA LAS COLUMNAS ESPECIALES
                        'Esta es la segunda columna (que acepta sólo números)
                        'repetimos el proceso de la primera columna pero en vez de ser
                        'DataGridTextBoxColumn será DataGridDigitsTextBoxColumn, que hemos definido
                        'en la clase DataGridDigitsTextBoxColumn del archivo DataGridDigitsTextBoxColumn.vb
                       
columna = New DataGridTextBoxColumnNumbers
                        columna.TextBox.MaxLength = 9
                        columna.Alignment = HorizontalAlignment.Left
                        columna.HeaderText = "Teléfono 1"
                       
'columna del Dataset enlazada con esta columna del Datagrid
                        columna.MappingName = "Teléfono1"
                        columna.Width = 100
                        'texto que se muestra cuando la columna tiene valor null
                        columna.NullText = ""
                        'añadir la columna a los estilos del Datagrid
                        estilo.GridColumnStyles.Add(columna)
 
                        'Esta es la tercera columna (que acepta sólo números)
                        'se crea igual que la segunda columna
                       
columna = New DataGridTextBoxColumnNumbers
                        columna.TextBox.MaxLength = 9
                        columna.Alignment = HorizontalAlignment.Left
                        columna.HeaderText = "Teléfono 2"
                       
'columna del Dataset enlazada con esta columna del Datagrid
                        columna.MappingName = "Teléfono2"
                        columna.Width = 100
                        'texto que se muestra cuando la columna tiene valor null
                        columna.NullText = ""
                        'añadir la columna a los estilos del Datagrid
                        estilo.GridColumnStyles.Add(columna)
 
                        'Añadir el estilo personalizado a la colección de estilos de tablas del Datagrid
                        Me.Grid.TableStyles.Add(estilo)

De esta manera tan sencilla conseguimos el efecto buscado y podemos comprobar fácilmente cómo las cajas de texto de Teléfono1 y de Teléfono2 no aceptan letras, en cambio el campo Nombre acepta letras y números indistintamente.
 

Ajustar los controles al formulario

Se ha configurado la propiedad Anchor de los controles para que, al maximizar el formulario, se conserve la disposición deseada. Como elemento estético, existe un control PictureBox con el logotipo miliuco que sólo se muestra con la ventana maximizada, utilizando el evento Datagrid_SizeChanged y la propiedad FormWindowState del formulario:

        'al maximizar el datagrid, mostrar el control PictureBox
       
'con la imagen de miliuco
        Private Sub Datagrid_SizeChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.SizeChanged
            If Me.WindowState = FormWindowState.Maximized Then
                Me.PictureBox1.Visible = True
            Else
                Me.PictureBox1.Visible = False

            End If
       End Sub
 


Imagen del DataGrid mostrando todos los campos de la tabla origen del DataSet:

Imagen del DataGrid mostrando los campos filtrados por la cadena de texto que el usuario teclea en un TextBox:

Imagen del DataGrid mostrando los campos filtrados al pulsar el botón I:


Pulsa aquí para ver el código completo.

Pulsa aquí para descargar la aplicación completa en Visual Studio 2003.