Agenda telefónica 2 y control 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
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:
