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/