O EFDataPager é um Web User Control que permite paginação com Entity Framework ou qualquer outro tipo de repositório de dados. A grande diferença entre este DataPager e o controlo standard que é disponibilizado no Visual Studio é que ao contrário do controlo standard este apenas vai buscar ao repositório de dados a informação que está a ser apresentada na página seleccionada, o que permite uma melhoria substancial na performance de acesso a dados e tempos de carregamento da página web.
Exemplo de uma ListView com o DataPager do VS2008:
Como se pode verificar na Imagem1 e Imagem2 acima apresentadas, quando estamos a utilizar o Standard DataPager para controlar a paginação de uma ListView, este carrega todos os dados do repositório e posteriormente organiza-os por páginas.
O maior problema de este controlo é que, em cada postback efectuado, é carregada novamente para a ListView a informação de todas as páginas mesmo que, como podemos ver na imagem2, apenas estejam a ser apresentados 3 registos ao utilizador. Como consequência o tempo de carregamento da página da página é penalizado, pois são carregadas informações que não vão ser apresentadas ao utilizador, o que gera um declínio na experiência de utilização.
Exemplo de uma ListView com o EFDataPager:
Por outro lado, ao utilizar o EFDataPager, apenas são carregados para a ListView os registos que são apresentados (Imagem3 e Imagem4), garantindo assim uma melhor experiência de utilização por parte do utilizador e um tempo de carregamento da página substancialmente menor.
Pode utilizar o EFDataPager com qualquer repositório de dados, incluindo com Entity Framework.
Implementação
Além de ser muito fácil de implementar o EFDataPager, é também um controlo extensível e facilmente personalizado para ir de encontro a necessidades mais específicas.
Para implementar o EFDataPager é necessário adicionar ao projecto o ficheiro ControloDataPager.ascx e o ficheiroPagerEventArgs.cs.
Depois é necessário, como em qualquer outro WebUserControl, registar o controlo na página em que este vai ser utilizado.
<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="ControloListView.ascx.cs" Inherits="EFDataPager.UserControls.ControloListView" %>
<%@ Register src="ControloDataPager.ascx" tagname="ControloDataPager" tagprefix="UserControl" %>
<h1>Notícias</h1>
<div class="noticias-pager">
<UserControl:ControloDataPager ID="ControloDataPager1" runat="server" ViewStateMode="Enabled" />
<asp:Label ID="NumberOfRowsLoadedFromDataSource" runat="server"></asp:Label>
<br />
<asp:Label ID="NumberOfRowsLoadedFromDataSourceEN" runat="server"></asp:Label>
</div>
<asp:ListView ID="listviewNoticias" runat="server" >
<LayoutTemplate>
<asp:PlaceHolder runat="server" ID="itemPlaceholder"></asp:PlaceHolder>
</LayoutTemplate>
<ItemTemplate>
<div class="noticias-title" >
<h3><%#Eval("Titulo")%></h3>
</div>
<div class="body-container">
<p><%#Eval("Descricao") %></p>
</div>
</ItemTemplate>
<EmptyItemTemplate>
<h1>Não existem notícias disponíveis neste momento.</h1>
</EmptyItemTemplate>
</asp:ListView>
Depois é necessário implementar o método RegistarEventos, utilizá-lo no Page_Load, implementar os eventos registados no método RegistarEventos e implementar o método CarregarDadosListview.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace EFDataPager.UserControls
{
using EFDataPager.BusinessObjects;
public partial class ControloListView : System.Web.UI.UserControl
{
protected void Page_Load(object sender, EventArgs e)
{
RegistarEventos();
ControloDataPager1.PageSize = 5;
ControloDataPager1.RowCount = GetNumberOfRows();
if (!Page.IsPostBack)
{
CarregarDadosListview(ControloDataPager1.PageSize, 0);
}
}
private void RegistarEventos()
{
ControloDataPager1.First += new ControloDataPager.ListViewPagerFirstHandler(ControloDataPager1_First);
ControloDataPager1.Previous += new ControloDataPager.ListViewPagerPreviousHandler(ControloDataPager1_Previous);
ControloDataPager1.Next += new ControloDataPager.ListViewPagerNextHandler(ControloDataPager1_Next);
ControloDataPager1.Last += new ControloDataPager.ListViewPagerLastHandler(ControloDataPager1_Last);
}
void ControloDataPager1_Last(object sender, PagerEventArgs e)
{
CarregarDadosListview(e.pageSize, e.currentRow);
}
void ControloDataPager1_Next(object sender, PagerEventArgs e)
{
CarregarDadosListview(e.pageSize, e.currentRow);
}
void ControloDataPager1_Previous(object sender, PagerEventArgs e)
{
CarregarDadosListview(e.pageSize, e.currentRow);
}
void ControloDataPager1_First(object sender, PagerEventArgs e)
{
CarregarDadosListview(e.pageSize, e.currentRow);
}
private void CarregarDadosListview(int pageSize, int currentRow)
{
var data = new DadosMock();
listviewNoticias.DataSource = data.ObterDadosMock(pageSize, currentRow).ToArray();
listviewNoticias.DataBind();
var nRows = data.ObterDadosMock(pageSize, currentRow).ToArray().Count();
NumberOfRowsLoadedFromDataSource.Text = string.Format("Número de elementos carregados: {0}", nRows);
NumberOfRowsLoadedFromDataSourceEN.Text = string.Format("Number of binded elements: {0}", nRows);
}
private int GetNumberOfRows()
{
var data = new DadosMock();
return data.ObterRowCount();
}
}
}
Está classe é um Mock para simular o comportamento de um repositório de dados.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace EFDataPager.BusinessObjects
{
public class DadosMock
{
public int ID { get; set; }
public string Titulo { get; set; }
public string Descricao { get; set; }
public DadosMock()
{
}
public DadosMock(int id, string title, string desc)
{
this.Descricao = desc;
this.ID = id;
this.Titulo = title;
}
public IQueryable<DadosMock> ObterDadosMock()
{
var lista = new List<DadosMock>();
for (int i = 0; i < 18; i++)
{
var item = new DadosMock(i, string.Format("Titulo {0}", i), string.Format("Descricao {0}", i));
lista.Add(item);
}
return lista.ToArray().AsQueryable();
}
public IQueryable<DadosMock> ObterDadosMock(int pageSize, int currentRow)
{
var lista = new List<DadosMock>();
//only for generate test data
for (int i = 0; i < 18; i++)
{
var item = new DadosMock(i, string.Format("Titulo {0}", i), string.Format("Descricao {1}", i, i));
lista.Add(item);
}
return lista.ToArray().Skip(currentRow).Take(pageSize).AsQueryable();
}
public int ObterRowCount()
{
return ObterDadosMock().Count();
}
}
}
Com o recurso ao linq, podemos facilmente controlar a paginação dos dados pedidos ao repositório de dados através dos métodos Skip e Take.
Demo: http://blastersystems.com/efdatapager/
O EFDataPager e o projecto vs2008 de teste estão disponíveis em:
http://efdatapager.codeplex.com/