Cómo enlazar una lista al control DataGridView |
Por Enrique Martínez Montejo |
Última revisión: 12/09/2010 |
Creo que son bastantes los usuarios que conocen la manera de enlazar un control DataGridView a un objeto DataTable. Basta con asignarle dicho objeto a la propiedad DataSource del control DataGridView. Pero, ¿y si no disponemos de un objeto DataTable? ¿Tendríamos que crear uno para mostrar una serie de datos?
Uno de los requisitos que debe de cumplir el objeto que se asigne a la propiedad DataSource del control DataGridView, es que su clase implemente alguna de las siguientes interfaces:
Los objetos DataSet, DataTable y BindingSource son de sobra conocidos como orígenes de datos del control DataGridView. Vamos a fijarnos en otros objetos no tan conocidos por los usuarios de Visual Basic .NET.
La versión 2.0 del marco de trabajo de .NET (Visual Studio 2005), introdujo una serie de clases genéricas para complementar las colecciones ya existentes en las versiones previas de la plataforma .NET. Entre ellas se encontraba la clase genérica List(Of T), que nos permite tener una lista de objetos de un determinado tipo de dato, lo que en el argot de .NET se conoce como una lista fuertemente tipificada, o tipada, como también se le denomina en ciertos medios.
Esto significa que la lista no puede contener objetos de diversos tipos (String, Integer, DateTime). El objeto List(Of T) sólo puede contener objetos de un mismo tipo, siendo la T la que define el tipo de dato que contendrá la lista: todos los elementos serán String, Integer o DateTime, obteniéndose una excepción en tiempo de diseño o compilación si algún objeto no es del tipo de dato definido al crear la lista.
Como la clase List(Of T) implementa la interfaz IList, entre otras más, cumple el requisito necesario para poder asignárselo a la propiedad DataSource del control DataGridView, tal y como muestra el siguiente ejemplo:
Dim paises
As New List(Of String)
paises.Add("España")
paises.Add("Francia")
paises.Add("Italia")
paises.Add("Alemania")
' Enlazamos el control DataGridView con la lista
genérica
DataGridView1.DataSource = paises
El resultado que se mostrará en el control DataGridView será el que aparece en la siguiente imagen:
Lo mismo se estará preguntando dónde están los nombres de los países que se han añadido a la lista genérica. Como podrá observar, solamente aparecen las longitudes de los nombres de los países que se han añadido a la lista, es decir, el valor devuelto por la propiedad Length de la clase System.String, que es el tipo de dato con el que se ha definido el objeto List(Of T). Como la clase System.String solamente dispone de una única propiedad que no necesita de ningún índice para obtener su valor, es por ello que únicamente se mostrarán en el control DataGridView los valores de dicha propiedad.
Es cierto que la clase System.String también dispone de la propiedad Chars, pero ésta necesita un índice para devolver el carácter (un valor Char) existente en el índice o posición indicado. Por éste motivo, los valores de ésta propiedad no se mostrarán en el control DataGridView.
Pero si en lugar de crear una lista genérica con tipos de datos String, la generamos utilizando estructuras DateTime, o cualquier otra clase o estructura definida por nosotros mismos, podremos observar los valores de muchas más propiedades:
Dim fechas
As New List(Of DateTime)
fechas.Add(New DateTime(1492, 10, 12))
fechas.Add(New DateTime(1776, 7, 4))
' Enlazamos el control DataGridView con la lista
genérica
DataGridView1.DataSource = fechas
' Eliminamos ciertas columnas
DataGridView1.Columns.Remove("Hour")
DataGridView1.Columns.Remove("Kind")
DataGridView1.Columns.Remove("Millisecond")
DataGridView1.Columns.Remove("Minute")
DataGridView1.Columns.Remove("Second")
Siendo el resultado el que aparece a continuación:
Esto viene a confirmar que el control DataGridView dispondrá de tantas columnas como propiedades públicas tenga el tipo de dato, o la estructura, con la que se ha definido la lista genérica List(Of T).
Todo esto está bien para mostrar un listado con los valores de la lista genérica definida, pero no podrá añadir nuevos registros al control DataGridView, ni tampoco eliminar los ya existentes, con lo cual no sabemos muy bien si nos puede ser de utilidad.
Como he mencionado al comienzo del artículo, otro requisito para poder enlazar un control DataGridView a un origen de datos, es que éste implemente la interfaz IBindingList, tal y como así lo hace la clase BindingList(Of T), que es la clase genérica del marco de trabajo de .NET que admite el enlace de datos, por tanto, la podemos utilizar en nuestras clases para proporcionar a las mismas un enlace de datos bidireccional.
Vamos a impletar la típica clase Cliente, la cual tendrá tres únicas propiedades públicas, a parte de su constructor predeterminado y de otro constructor sobrecargado.
Public Class Cliente
Private m_idCliente
As Integer
Private m_nombre
As String
Private m_direccion
As String
Public Sub New()
' Constructor
por defecto. Es necesario para
' poder añadir nuevos registros en
blanco.
End Sub
Public Sub New(ByVal
idcliente As Integer,
ByVal
nombre As String,
ByVal
direccion As String)
m_idCliente = idcliente
m_direccion = direccion
m_nombre = nombre
End Sub
Public Property IdCliente
As Integer
Get
Return m_idCliente
End Get
Set(ByVal
value As Integer)
m_idCliente =
value
End Set
End Property
Public Property Nombre
As String
Get
Return m_nombre
End Get
Set(ByVal
value As String)
m_nombre =
value
End Set
End Property
Public Property Direccion
As String
Get
Return m_direccion
End Get
Set(ByVal
value As String)
m_direccion =
value
End Set
End Property
End Class
Podríamos crear una lista genérica del tipo List(Of Cliente) tal y como he explicado en el apartado anterior. Pero estaríamos en las mismas: no se podrán añadir nuevos registros al control DataGridView.
Para solventar éste impedimento necesitamos de una clase intermedia que nos proporcione un enlace de datos, y que disponga de un evento para añadir nuevos registros, en nuestro caso, nuevos objetos del tipo Cliente. Y esta clase bien pudiera ser cualquiera que herede de la clase System.ComponentModel.BindingList(Of T):
Imports System.ComponentModel
Public Class ListaClientes
' La clase admitirá el enlace de datos
Inherits BindingList(Of Cliente)
Protected Overrides Sub
OnAddingNew(ByVal e
As
AddingNewEventArgs)
' Creamos un
nuevo Cliente
'
e.NewObject =
New Cliente()
End Sub
End Class
Esta clase derivada, a parte de la funcionalidad existente en el objeto BindingList(Of T), hará que se desencadene el evento AddingNew cada vez que se desee crear un nuevo registro en el control DataGridView, de ahí que se reemplace el método OnAddingNew para asignarle una nueva instancia de la clase Cliente a la propiedad NewObject del objeto AddingNewEventArgs.
Una vez que tenemos creadas ambas clases (Cliente y ListaClientes), ya es hora de enlazar un objeto BindingList(Of T) con un control DataGridView. Para ello, simplemente ejecutaría lo siguiente:
' Construimos una lista de clientes
Dim lst As ListaClientes
= New ListaClientes()
' Añadimos clientes a la lista
lst.Add(New Cliente(43001,
"José Amate", "C/. García Benítez, 23"))
lst.Add(New Cliente(43002,
"Felipe Moya", "C/. Isaac Peral, 56"))
lst.Add(New Cliente(43003,
"Carmen Díaz", "C/. Ruiz Romero, 85"))
' Enlazamos el control DataGridView con la lista
DataGridView1.DataSource = lst
Y aquí tiene el resultado:
Como podrá observar en la imagen, el cuarto registro está siendo añadido actualmente al control DataGridView. Asimismo, podrá editar cualquier registro existente, al igual que eliminar cualquiera de ellos. Los cambios que efectúe en el control DataGridView, automáticamente se actualizarán en la lista genérica definida, que podrá referenciarla ejecutando la siguiente asignación:
' Referenciamos el origen de datos del control
DataGridView.
'
Dim lst
As ListaClientes
= DirectCast(DataGridView1.DataSource,
ListaClientes)
' Recorremos sus elementos
'
For Each item
As Cliente
In lst
Console.WriteLine("{0} {1} {2}",
item.IdCliente, item.Nombre, item.Direccion)
Next
Otros enlaces de interés:
Índice de la colección de ejemplos de las clases del marco de trabajo de .NET
Enrique Martínez Montejo - 2010
NOTA: La información contenida en este artículo, así como el código fuente incluido en el mismo, se proporciona COMO ESTÁ, sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo explicado, recomendado o sugerido en el presente artículo.
NOTE: The information contained in this article and source code included therein, is provided AS IS without warranty of any kind, and confers no rights. You assume any risk to implement, use or run it explained, recommended or suggested in this article.