DataGrid y paginación en ASP .NET con C# y VB

Mostrar una base de datos de Microsoft Access dentro de una página ASPX en un DataGrid con paginación para mostrar en cada página un número limitado y definido de registros y desplazarse entre las distintas páginas mediante botones de navegación, en Visual Studio 2017 con C# y VB

En este ejercicio nos conectamos con una base de datos de Microsoft Access y, por código, creamos un DataGrid en el que se activa la paginación. El DataGrid tiene opciones de configuración del número de registros por página, número de botones de navegación y su posición, botones numéricos o de flecha, diseño (tipo de fuente, colores de fondo, bordes, formato diferente en cabecera, cuerpo y pie, anchura de las columnas), etc.

La base de datos llamada 500empresas es un ejemplo con 500 nombres de empresas y 2 teléfonos (ficticios) de forma que la única tabla se llama Contactos y las 3 columnas se llaman Nombre, Teléfono1 y Teléfono2. Las 3 columnas han de ser mostradas en el DataGrid obteniendo los registros con sentencias SQL que se pasan mediante objetos OleDbDataAdapter.

Página ASPX

La paginación se activa en la etiqueta asp:DataGrid con las propiedades AllowPaging=»True» y PageSize=»15″. El evento de cambio de página del Datagrid es OnPageIndexChanged y, al detectarlo, se llama al método que se ejecutará al cambiar de índice.

<asp:datagrid id="Rejilla"
	runat="server"
	allowpaging="True"
	pagesize="20"
	onpageindexchanged="Rejilla_IndexChanged">

El tipo y número de botones de navegación se configuran en la etiqueta PagerStyle mediante los atributos pagebuttoncount y mode.

<pagerstyle mode="NumericPages" pagebuttoncount="10" mode="NumericPages"></PagerStyle> 

En la página de código C# hay que generar el método para controlar los eventos de paginado del DataGrid. Nos moveremos por las distintas páginas del DataGrid detectando su evento PageChanged y modificando la propiedad CurrentPageIndex para establecer la página seleccionada por el usuario.

public void Rejilla_IndexChanged(object obj, DataGridPageChangedEventArgs e)
{
    Rejilla.CurrentPageIndex = e.NewPageIndex;
    Rejilla.DataBind();
}

En la página ASPX se configuran 3 botones que, al ser pulsados, desencadenan un método que ordena los registros con parámetros diferentes. Cada botón se relaciona con cada una de las columnas del DataGrid y ordena los registros por el nombre de cada una de las columnas de la tabla.

<asp:button id="BtNombre" runat="server" text="Ordenar por Nombre" OnClick="BtNombre_Click" /></td>
<asp:button id="BtTel1" runat="server" text="Ordenar por Teléfono 1" OnClick="BtTel1_Click" /></td>
<asp:button id="BtTel2" runat="server" text="Ordenar por Teléfono 2" OnClick="BtTel2_Click" /></td>

Conexión a la base de datos

El formato antiguo de Access tenía la extensión MDB y para conectar con este tipo de archivo hay que utilizar el motor de bases de datos Jet. En cambio el formato actual tiene la extensión ACCDB y el motor Jet no sirve para la conexión, hay que usar el motor más moderno ACE (Access Database Engine). ACE es compatible con lo anterior de forma que ACE puede conectar con MDB y ACCDB pero Jet sólo puede conectar con MDB.
En este ejercicio he configurado las 2 opciones para que con poner o quitar el comentario a una línea se pueden probar ambos formatos de base de datos (el proyecto contiene las 2 versiones). Con las variables ruta y proveedor se construye la cadena de conexión.

//Para construir la cadena de conexión a la BD:
//archivo MDB usa Microsoft.Jet.OLEDB.4.0 y archivo ACCDB usa Microsoft.ACE.OleDb.12.0
private string ruta = AppDomain.CurrentDomain.BaseDirectory + "500empresas.mdb";
//private string proveedor = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=";
private string proveedor = "Provider=Microsoft.ACE.OleDb.12.0;Data Source=";
//cadena de conexión construida con 2 variables ya establecidas
conn.ConnectionString = "" + proveedor + ruta + "";

El proceso de conexión y de carga de datos para ser mostrados en el Datagrid se realiza por pasos:

  • el objeto OleDbDataAdapter usa la cadena de conexión para conectar con la BD y mediante un comando SQL obtiene los registros
  • no es necesario abrir y cerrar explícitamente la conexión porque OleDbDataAdapter se encarga de esta tarea automáticamente
  • los registros obtenidos desde la tabla se pasan al DataSet que funciona como una memoria intermedia
  • el DataSet rellena el DataGrid con la tabla especificada y mediante el método DataBind() se realiza el enlace entre ambos.
//OleDbDataAdapter con el comando SQL que coge todos los registros y los ordena por Nombre
adaptador = new OleDbDataAdapter("SELECT * FROM Contactos ORDER BY Nombre", conn);
//objeto que mantiene en memoria los datos, es el almacén desconectado de los datos
datos = new DataSet();
//el adaptador OleDbDataAdapter abre y cierra la conexión con el origen de los datos
//no es necesario abrirla y cerrarla explícitamente
//conn.Open()
//OleDbDataAdapter rellena el DataSet con la tabla seleccionada
adaptador.Fill(datos, "Contactos");
//rellenar el DataGrid
Rejilla.DataSource = datos.Tables[0];
DataBind();
//conn.Close()

Mostrar el número de registros

Se muestra el nº total de registros del DataGrid contando todas las filas de la tabla y también se muestra el nº de registros por página obtenido desde la propiedad PageSize del DataGrid. A las etiquetas de la página ASPX se les puede pasar texto HTML como parte de la cadena que se construye, esto permite formatear lo que se muestra en la etiqueta.

//mostrar el nº total de registros del DataGrid contando todas las filas de la tabla
//y el nº de registros por página obtenido de la propiedad PageSize del DataGrid
int n = datos.Tables["Contactos"].Rows.Count;
int p = Rejilla.PageSize;
LbTotal.Text = "Número de registros en el DataGrid: <br/><b>" + "" + n.ToString() + "</b><br/> Número de registros por página: <br/><b>" + "" + p.ToString() + "</b>";
LbAviso.Text = "Ruta actual a la base de datos: <br/><i>" + ruta + "</i>";

Botones de ordenación

Al pulsar cada uno de los 3 botones de ordenación se llama al método que abre la conexión con un objeto OleDbDataAdapter al que se pasa el comando SQL requerido para seleccionar de nuevo los registros, ordenándolos por el nombre de una de las columnas de la tabla, llenando el DataSet y el DataGrid con el origen de datos pero con la nueva definición de ordenación. Por ejemplo, al pulsar el botón «Ordenar por Nombre»:

//cadena de conexión construida con 2 variables ya establecidas
conn.ConnectionString = "" + proveedor + ruta + "";
//OleDbDataAdapter con el comando SQL que coge todos los registros y los ordena por Nombre
adaptador = new OleDbDataAdapter("SELECT * FROM Contactos ORDER BY Nombre", conn);
datos = new DataSet();
//el adaptador OleDbDataAdapter abre y cierra la conexión con el origen de los datos
//conn.Open()
adaptador.Fill(datos, "Contactos");
Rejilla.DataSource = datos.Tables["Contactos"];
DataBind();
//conn.Close()

Cambiar por código el texto de controles del DataGrid

El DataGrid incorpora en sus controles de paginación el llamado DataGridLinkButton, se trata de esos 3 puntos que aparecen a izquierda y derecha de los números de las páginas y que permiten desplazarse hacia adelante o hacia atrás. A mí me gusta más que se vean las palabras Siguiente y Anterior en lugar de los 3 puntos. Pero este texto del control ya no es posible modificarlo de forma sencilla en las propiedades del DataGrid. Hay que hacerlo de otra manera.

En Visual Basic he utilizado la expresión DirectCast que define una operación de conversión de tipos y se utiliza de forma similar a la palabra clave CType pero se diferencia en que CType se ejecuta bien si hay una conversión válida pero DirectCast requiere que un tipo se herede del otro tipo o lo implemente. DirectCast se emplea en un método que se ejecuta cuando se crea el DataGrid (al detectar el evento ItemCreated del DataGrid). Las dos palabras clave toman como primer argumento una expresión para convertirla y como segundo argumento el tipo al que se va a convertir dicha expresión. Si no hay ninguna conversión definida entre el tipo de datos de la expresión y el tipo de datos especificado como segundo argumento, las dos conversiones fallan.

En C# he usado la expresión Parse, detectando el control DataGridLinkButton y la propiedad texto que es (los 3 puntos suspensivos) para reemplazarlos por Anterior o Siguiente dependiendo de si dirige a la página anterior o no.

protected void Rejilla_ItemCreated1(object sender, DataGridItemEventArgs e)
{
    if (e.Item.ItemType == ListItemType.Pager)
    {
	foreach (System.Web.UI.WebControls.TableCell cont in e.Item.Controls)
	{
	    foreach (System.Web.UI.Control cont2 in cont.Controls)
	    {
		if (cont2.GetType().ToString() == "System.Web.UI.WebControls.DataGridLinkButton")
		{
		    if (((System.Web.UI.WebControls.LinkButton)cont2).Text == "...")
		    {
			string pag = ((System.Web.UI.WebControls.LinkButton)cont2).CommandArgument;
			if (int.Parse(pag) <= Rejilla.CurrentPageIndex)
			{
			    ((System.Web.UI.WebControls.LinkButton)cont2).Text = "Anterior";
			}
			else
			{
			    ((System.Web.UI.WebControls.LinkButton)cont2).Text = "Siguiente";
			}
		    }
		}
	    }
	}
    }
}
Private Sub Rejilla_ItemCreated(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.DataGridItemEventArgs) Handles Rejilla.ItemCreated
        If e.Item.ItemType = ListItemType.Pager Then
            For Each cont As System.Web.UI.WebControls.TableCell In e.Item.Controls
                For Each cont2 As System.Web.UI.Control In cont.Controls
                    If cont2.GetType.ToString = "System.Web.UI.WebControls.DataGridLinkButton" Then
                        If DirectCast(cont2, System.Web.UI.WebControls.LinkButton).Text = "..." Then
                            Dim pag As String = DirectCast(cont2, System.Web.UI.WebControls.LinkButton).CommandArgument
                            If Integer.Parse(pag) <= Rejilla.CurrentPageIndex Then
                                DirectCast(cont2, System.Web.UI.WebControls.LinkButton).Text = "Anterior"
                            Else
                                DirectCast(cont2, System.Web.UI.WebControls.LinkButton).Text = "Siguiente"
                            End If
                        End If
                    End If
                Next
            Next
        End If
    End Sub

En esta imagen se observa el aspecto de los controles en su forma estándar y con el bloque de código propuesto:

Puedes descargar un archivo ZIP con las aplicaciones C# y VB.

2 comentarios en «DataGrid y paginación en ASP .NET con C# y VB»

  1. Yo también suelo hacerlo así, pero al publicar en WordPress empleo el plugin Syntax HighLighter Evolved para mostrar los bloques de código coloreados y más bonitos y este plugin cuando escribo & lo muestra como su código HTML. Lo cambio sólo para mostrar bien los bloques de código pero en Visual Studio sigo empleando casi siempre & en lugar de +.

  2. En VB por qué escribes proveedor + ruta en lugar de proveedor & ruta sin más? Para unir cadenas siempre empleo el carácter &.

Los comentarios están cerrados.