Cómo crear tablas dinámicas con el control ListView en ASP.NET Web Forms

A día de hoy, decidir que tipo de patrón de diseño utilizaríamos para desarrollar una aplicación Web en .NET es una elección de sentido común. En mi opinión, ASP.NET MVC es la mejor alternativa para la gran mayoría de nuevos desarrollos que vayamos a emprender.

Aún así, existen casos en los que recurrir a los clásicos Web Forms, es una opción más que aceptable por su sencillez y por esa 'orientación a eventos' que nos recuerda a las antiguas aplicaciones de escritorio (Windows Forms). Cuando necesitemos desarrollar una aplicación de gestión que se ejecute bajo un entorno corporativo (Intranet) con un número limitado de usuarios, ASP.NET Web Forms es sin duda la alternativa recomendada. En este Post de 'buenas prácticas', veremos cómo crear tablas HTML de forma dinámica a partir de un origen de datos, utilizando el control Web ListView de ASP.NET Web Forms.

El control Web ListView, permite ser integrado y configurado de múltiples formas en una página web aspx de Web Forms. La ventaja de este control es que permite 'iterar' elementos de cualquier tipo ya que funciona con templates (plantillas).

Buenas prácticas

Microsoft pone a disposición de la comunidad de programadores ASP.NET infinidad de ejemplos de como configurar un control ListView en función de las necesidades y características de cada aplicación. A continuación veremos la manera correcta (según mi experiencia) de crear tablas HTML con paginación, utilizando el control ListView y los controladores de 'eventos de servidor' que nos proporcionan las páginas aspx.

Tabla Html con ListView ejemplo

Los elementos visuales (index.aspx)

En primer lugar definiremos los elementos visuales (controles Web y Html) de nuestra página de ejemplo index.aspx. Utilizaremos los controles <asp:ListView runat="server"> y <asp:PlaceHolder runat="server"> para crear la tabla Html, y el control <asp:DataPager runat="server"> para el paginador. Utilizaremos Bootstrap 3.2 para dar formato y estilos a la página.

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Index.aspx.cs" 
         Inherits="BLOG_ListView.Index" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title>Creando tablas dinámicas con el control ListView en ASP.NET WebForms</title>
    <link href="Content/bootstrap.min.css" rel="stylesheet" type="text/css" />
</head>
<body>
    <form runat="server" id="form1">        
        <div class="container">
            <h2>Tabla Customers</h2>
            <%--Control de servidor ListView--%>
            <asp:ListView runat="server" ID="TableListView" 
                          ItemPlaceholderID="itemPlaceHolder" 
                          OnItemDataBound="MyListView_ItemDataBound">
                <%--Plantilla de diseño de la tabla Html--%>
                <LayoutTemplate>
                    <table id="ListViewTable" class="table table-bordered">
                        <%--Cabecera de la tabla Html--%>
                        <thead>
                            <tr>
                                <th scope="col">Contact name</th>
                                <th scope="col">Company name</th>
                                <th scope="col">Email</th>
                            </tr>
                        </thead>
                        <%--Cuerpo de la tabla Html--%>
                        <tbody>
                            <%--Control de servidor PlaceHolder, elemento que
                            contendrá la plantilla <ItemTemplate>--%>
                            <asp:PlaceHolder runat="server" id="itemPlaceHolder">
                            </asp:PlaceHolder>
                        </tbody>
                    </table>
                </LayoutTemplate>
                <%--Plantilla de los elementos dinámicos de la tabla Html
                filas y columnas--%>
                <ItemTemplate>
                    <tr>                                
                        <td runat="server" id="ContactName"></td>
                        <td runat="server" id="CompanyName"></td>
                        <td runat="server" id="Email"></td>
                    </tr>
                </ItemTemplate>            

            </asp:ListView>

            <%--Control de servidor DataPager, paginador de la tabla Html--%>
            <asp:DataPager runat="server" ID="TableDataPager" 
                           PagedControlID="TableListView" PageSize="10">
                <Fields>                        
                    <asp:NextPreviousPagerField ButtonType="Button"
                                                ShowFirstPageButton="True" 
                                                ShowNextPageButton="False" 
                                                PreviousPageText="&#9668;" 
                                                FirstPageText="&#9668;&#9668;"
                                                ButtonCssClass="btn btn-sm btn-default"/>
                    <asp:NumericPagerField ButtonType="Button"
                                           NumericButtonCssClass="btn btn-sm btn-default" 
                                           CurrentPageLabelCssClass=""
                                           NextPreviousButtonCssClass="btn btn-sm btn-default"/>
                    <asp:NextPreviousPagerField ButtonType="Button"
                                                ShowLastPageButton="True" 
                                                ShowPreviousPageButton="False" 
                                                NextPageText="&#9658;" 
                                                LastPageText="&#9658;&#9658;"
                                                ButtonCssClass="btn btn-sm btn-default"/>
                </Fields>
            </asp:DataPager> 
        </div>
    </form>

    <script src="Scripts/jquery-1.9.1.min.js"></script>
    <script src="Scripts/bootstrap.min.js"></script>
</body>
</html>

El CodeBehind (index.aspx.cs)

Una vez definidos los elementos visuales, pasaremos a escribir el código de servidor (CodeBehind) que enlazará el 'origen de datos' a la tabla Html generada por el control ListView. Es de vital importancia que la codificación se realice en un orden determinado y en el controlador de eventos adecuado para cada acción:

1. Carga de datos

En el evento Page_Load de la página aspx, cargamos en una variable local el origen de datos utilizando EntityFramework. Para este ejemplo hemos utilizado el modelo de datos 'Customers' de la base de datos de pruebas Northwind de Microsoft (modelo disponible para descargar al final del Post).

protected void Page_Load(object sender, EventArgs e)
{            
  _customers = _dataModel.Customers.OrderBy(x => x.ContactName).ToList();
}
2. Enlace de datos

En el evento OnPreRender de la página aspx, asignamos los datos del modelo a la propiedad DataSource del control ListView y los 'enlazamos' mediante el método DataBind(). 

// Tener en cuenta que es un método 'override'
protected override void OnPreRender(EventArgs e)
{
   base.OnPreRender(e);
   TableListView.DataSource = _customers;
   TableListView.DataBind();
}
3. Asignación de datos

En el evento ItemDataBound (al enlazar los datos) del control ListView, asignamos a cada celda de la tabla (HtmlTableCell) los valores correspondientes del modelo de datos.

protected void TableListView_ItemDataBound(object sender, ListViewItemEventArgs e)
{
  if (e.Item.ItemType == ListViewItemType.DataItem)
  {
    Customer _customer =  (Customer)e.Item.DataItem;
    ((HtmlTableCell)e.Item.FindControl("ContactName")).InnerText = _customer.ContactName;
    ((HtmlTableCell)e.Item.FindControl("CompanyName")).InnerText = _customer.CompanyName;
    ((HtmlTableCell)e.Item.FindControl("Email")).InnerText = _customer.Email;
  }
}

El código completo de index.aspx.cs a continuación:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;

namespace BLOG_ListView
{
    public partial class Index : System.Web.UI.Page
    {
        private DataModel _dataModel;
        private List<Customer> _customers;

        public Index()
        {
            _dataModel = new DataModel();
            _customers = new List<Customer>();
        }        

        protected void Page_Load(object sender, EventArgs e)
        {            
            _customers = _dataModel.Customers.OrderBy(x => x.ContactName).ToList();
        }

        // Tener en cuenta que es un método 'override'
        protected override void OnPreRender(EventArgs e)
        {
            base.OnPreRender(e);
            TableListView.DataSource = _customers;
            TableListView.DataBind();
        }

        protected void TableListView_ItemDataBound(object sender, ListViewItemEventArgs e)
        {
            if (e.Item.ItemType == ListViewItemType.DataItem)
            {
                Customer _customer =  (Customer)e.Item.DataItem;
                ((HtmlTableCell)e.Item.FindControl("ContactName")).InnerText = _customer.ContactName;
                ((HtmlTableCell)e.Item.FindControl("CompanyName")).InnerText = _customer.CompanyName;
                ((HtmlTableCell)e.Item.FindControl("Email")).InnerText = _customer.Email;
            }
        }
    }
}

Descargas

Modelo de datos - dbo.Customers.sql
Datos de prueba - dbo.Customers.data.sql

   EtiquetasASP.NET Web Forms C#

  Compartir


  Nuevo comentario

El campo Comentario es obligatorio.
El campo Nombre es obligatorio.

  Comentarios

Rafael Administrador Rafael

@Julio Tristán:
Gracias por tu comentario. Efectivamente tienes razón en lo que dices, pero ten en cuenta que este Post lo que intenta es explicar como crear tablas de manera dinámica con el control ListView y no como crear un sistema de paginación. Como bien dices cada vez que cambiamos de página realizamos un 'Postback' al servidor y al entrar en el evento 'Page_Load' volvemos a traer toda la tabla 'Customers' de la base de datos, y esto para un gran volumen de datos no es práctico.
Una solución a este problema sería realizar un filtro previo a los datos, como por ejemplo una búsqueda por texto que reduciría el volumen de datos a mostrar, esto es lo que normalmente se hace en una aplicación real.
Por último comentar que en breve publicaré un Post donde veremos como crear un sistema de paginación completo para aplicaciones ASP.NET MVC.
Julio Trist&#225;n Julio Tristán

Hola,
He probado el código y funciona perfectamente. Pero veo que cada vez que cambio de página con el paginador siempre se vuelven a cargar todos los datos de la tabla desde la base de datos, y esto no es óptimo. Existe alguna forma de traer de la base de datos solo los datos necesarios para cada página? no se si me he explicado bien.
Muchas gracias.


Utilizamos cookies propias y de terceros para mejorar nuestros servicios y ofrecerle una mejor experiencia de navegación. Si continúa navegando consideramos que acepta su uso. Más información   Acepto