Menu

Paginado eficiente de grillas Parte 2/2

Octubre 6, 2013 - ASP.NET

Continuando con el paginado eficiente en grillas procederemos a realizar la interfaz de usuario, para el ejemplo usaremos un GridView y un Repeater, si bien desde la versión 3.5 se implemento un control llamado DataPager especialmente creado para este fin, he querido utilizar el Repeater y hacerlo a la vieja usanza, así cuando tengamos que usar el DataPager será pan comido.

Resultado

Al finalizar nuestro tutorial veremos esto:

Untitled

¿A que no adivinas cuantos registros tengo?

Lo primero que vamos a implementar es el Repeater con la cantidad de paginas necesarias para mostrar todos los datos, para ello utilizare dos metodos:

private int GetTotalRecords()
{
  int TotalRecords;
  using (SqlConnection Connection = new SqlConnection(ConfigurationManager.ConnectionStrings["AdventureWorks2012ConnectionString"].ConnectionString))
  {
    Connection.Open();
    SqlCommand Query = new SqlCommand("uspTotalRecordCount", Connection);
    TotalRecords = Convert.ToInt32(Query.ExecuteScalar());
  }
  return TotalRecords;
}

Que como vemos usa el procedimiento almacenado uspTotalRecordCount y simplemente devuelve el total de los registros de la consulta.

private void PopulatePager(int CurrentPage)
{
  int PageSize = grdPersons.PageSize;
  int TotalRecords = GetTotalRecords();
  int TotalPages = (int)Math.Ceiling((decimal)TotalRecords / PageSize);
  List Pages = new List();
  Pages.Add(new ListItem(String.Format("First"), "1", CurrentPage > 1));
  for (int i = 1; i <= TotalPages; i++)
  {
    Pages.Add(new ListItem(i.ToString(), i.ToString(), i != CurrentPage));
  }
  Pages.Add(new ListItem(String.Format("Last"), TotalPages.ToString(), CurrentPage < TotalPages));
  rptPager.DataSource = Pages;
  rptPager.DataBind();
}

En este método sucede la gran mayoría de la magia del paginado, primero vemos la variable TotalPages que simplemente divide el total de registros entre la cantidad de registros mostrados por pagina en este caso seria: 19972 / 10 = 1997,2 pero como no podemos mostrar ,2 registros hacemos un redondeo hacia arriba dejando en total la variable en 1998, así en la ultima pagina se mostraran solo 2 registros. Por otro lado tenemos la variable Pages que es una lista de ListItems, ¿Por qué ListItems?, porque me permiten tener un ‘texto’ y un ‘valor’ que será muy útil para colocar los valores de ‘First’ y ‘Last’ en el Repeater, así lo único que hacemos es crear un ciclo en el que creamos todas las paginas que están en la variable TotalPages, no sin antes del ciclo crear el ‘First’ y al final del ciclo crear el ‘Last’. Por último recalcar el tercer parámetro que indica si el ListItem esta activo, la lógica en el es si la pagina actual es la que se esta creando en el Repeater.

Luego de haber creado los métodos para crear la lógica del Repeater vamos a crear su layout ya que el control Repeater no tiene representación visual, debemos crearla manualmente nosotros, así:

<asp:Repeater ID="rptPager" runat="server">
  <ItemTemplate>
    <asp:LinkButton runat="server" Text='<%#Eval("Text") %>' CommandArgument='<%# Eval("Value") %>' Enabled='<%# Eval("Enabled") %>' OnClick="Page_Changed" Font-Size="X-Small">
    </asp:LinkButton>
  </ItemTemplate>
</asp:Repeater>

Como podemos ver lo único ‘raro’ que tenemos son los Eval que lo que hacen es evaluar propiedades de cada uno de los ListItem, Text para el texto, Value para el valor (CommandArgument) y Enables para activar o no el numero dependiendo en que pagina estemos. Además debemos tener un método para el cambio de pagina que se manejara mediante el evento OnClick del control:

protected void Page_Changed(object sender, EventArgs e)
{
  int PageIndex = Convert.ToInt32((sender as LinkButton).CommandArgument);
  GetData(PageIndex);
  PopulatePager(PageIndex);
}

Cada vez que el usuario cambia de pagina lo que hago es tomar el CommandArgument que tiene el valor de la pagina actual y se la envío a los metodos de GetData y PopulatePager.

En el método de GetData lo único que hago es obtener los datos a mostrar en la grilla:

private void GetData(int PageIndex)
{
  int PageSize = grdPersons.PageSize;
  int StartRowIndex = (PageIndex - 1) * PageSize + 1;
  using (SqlConnection Connection = new SqlConnection(ConfigurationManager.ConnectionStrings["AdventureWorks2012ConnectionString"].ConnectionString))
  {
    Connection.Open();
    SqlCommand Query = new SqlCommand("uspGetPersonPaged", Connection);
    Query.CommandType = CommandType.StoredProcedure;
    SqlParameter ParamStartRowIndex = new SqlParameter("@StartRowIndex", StartRowIndex);
    SqlParameter ParamMaximumRows = new SqlParameter("@MaximumRows", PageSize);
    Query.Parameters.Add(ParamStartRowIndex);
    Query.Parameters.Add(ParamMaximumRows);
    grdPersons.DataSource = Query.ExecuteReader();
    grdPersons.DataBind()
  }
}

Lo único remarcable aquí es la variable StartRowIndex que se calcula con la pagina actual – 1 y multiplicándolo por el PageSize + 1.

Por último les dejo el PageLoad que lo único que hace es llamar el PopulatePager y GetData en 1.

protected void Page_Load(object sender, EventArgs e)
{
  if (IsPostBack == false)
  {
    PopulatePager(1);
    GetData(1);
  }
}

Al final nos de todo esto nos mostrara un repeater con 1980 paginas (Sí, sé que son demasiadas) y un GridView que muestra los datos de la pagina escogida de forma eficiente.

Pueden descargarse el proyecto EfficientPaging.

Y como siempre… Happy coding!!! Risa

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *