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/
Thanks for writing this datapager. Can’t believe the asp.net datapager is so horrible
One bug though…if you go to your demo page and let the session expire (leave the browser window open for a while) then click on the next or prev buttons, you’ll get a runtime error…
Thanks Ken, i’m going to update in the next days the UserControl in CodePlex because i found a simpler and reliable way to implement this type of control.