asp.net中让Repeater和GridView支持DataPager分页

  改造办法是自己写一个控件,让它继承GridView或Repeater,并实现IPageableItemContainer 接口。下面要发的是国外某高手写的代码,测试有效。具体使用的时候,要建一个类库项目,把代码编译成dll后,就可以添加到VS的工具箱里了!

  一、自定义Repeater

  

复制代码 代码如下:

  using System.Web.UI;

  using System.Web.UI.WebControls;

  namespace WYJ.Web.Controls

  {

  /// <summary>

  /// Repeater with support for DataPager

  /// </summary>

  [ToolboxData("<{0}:DataPagerRepeater runat=server PersistentDataSource=true></{0}:DataPagerRepeater>")]

  public class DataPagerRepeater : Repeater, System.Web.UI.WebControls.IPageableItemContainer, INamingContainer

  {

  /// <summary>

  /// Number of rows to show

  /// </summary>

  public int MaximumRows { get { return ViewState["MaximumRows"] != null ? (int)ViewState["MaximumRows"] : -1; } }

  /// <summary>

  /// First row to show

  /// </summary>

  public int StartRowIndex { get { return ViewState["StartRowIndex"] != null ? (int)ViewState["StartRowIndex"] : -1; } }

  /// <summary>

  /// Total rows. When PagingInDataSource is set to true you must get the total records from the datasource (without paging) at the FetchingData event

  /// When PagingInDataSource is set to true you also need to set this when you load the data the first time.

  /// </summary>

  public int TotalRows { get { return ViewState["TotalRows"] != null ? (int)ViewState["TotalRows"] : -1; } set { ViewState["TotalRows"] = value; } }

  /// <summary>

  /// If repeater should store data source in view state. If false you need to get and bind data at post back. When using a connected data source this is handled by the data source.

  /// </summary>

  public bool PersistentDataSource

  {

  get { return ViewState["PersistentDataSource"] != null ? (bool)ViewState["PersistentDataSource"] : true; }

  set { ViewState["PersistentDataSource"] = value; }

  }

  /// <summary>

  /// Set to true if you want to handle paging in the data source.

  /// Ex if you are selecting data from the database and only select the current rows

  /// you must set this property to true and get and rebind data at the FetchingData event.

  /// If this is true you must also set the TotalRecords property at the FetchingData event.

  /// </summary>

  /// <seealso cref="FetchingData"/>

  /// <seealso cref="TotalRows"/>

  public bool PagingInDataSource

  {

  get { return ViewState["PageingInDataSource"] != null ? (bool)ViewState["PageingInDataSource"] : false; }

  set { ViewState["PageingInDataSource"] = value; }

  }

  /// <summary>

  /// Checks if you need to rebind data source at postback

  /// </summary>

  public bool NeedsDataSource

  {

  get

  {

  if (PagingInDataSource)

  return true;

  if (IsBoundUsingDataSourceID == false && !Page.IsPostBack)

  return true;

  if (IsBoundUsingDataSourceID == false && PersistentDataSource == false && Page.IsPostBack)

  return true;

  else

  return false;

  }

  }

  /// <summary>

  /// Loading ViewState

  /// </summary>

  /// <param name="savedState"></param>

  protected override void LoadViewState(object savedState)

  {

  base.LoadViewState(savedState);

  //if (Page.IsPostBack)

  //{

  // if (!IsBoundUsingDataSourceID && PersistentDataSource && ViewState["DataSource"] != null)

  // {

  // this.DataSource = ViewState["DataSource"];

  // this.DataBind(true);

  // }

  // if (IsBoundUsingDataSourceID)

  // {

  // this.DataBind();

  // }

  //}

  }

  protected override void OnLoad(System.EventArgs e)

  {

  if (Page.IsPostBack)

  {

  if (NeedsDataSource && FetchingData != null)

  {

  if (PagingInDataSource)

  {

  SetPageProperties(StartRowIndex, MaximumRows, true);

  }

  FetchingData(this, null);

  }

  if (!IsBoundUsingDataSourceID && PersistentDataSource && ViewState["DataSource"] != null)

  {

  this.DataSource = ViewState["DataSource"];

  this.DataBind();

  }

  if (IsBoundUsingDataSourceID)

  {

  this.DataBind();

  }

  }

  base.OnLoad(e);

  }

  /// <summary>

  /// Method used by pager to set totalrecords

  /// </summary>

  /// <param name="startRowIndex">startRowIndex</param>

  /// <param name="maximumRows">maximumRows</param>

  /// <param name="databind">databind</param>

  public void SetPageProperties(int startRowIndex, int maximumRows, bool databind)

  {

  ViewState["StartRowIndex"] = startRowIndex;

  ViewState["MaximumRows"] = maximumRows;

  if (TotalRows > -1)

  {

  if (TotalRowCountAvailable != null)

  {

  TotalRowCountAvailable(this, new PageEventArgs((int)ViewState["StartRowIndex"], (int)ViewState["MaximumRows"], TotalRows));

  }

  }

  }

  /// <summary>

  /// OnDataPropertyChanged

  /// </summary>

  protected override void OnDataPropertyChanged()

  {

  if (MaximumRows != -1 || IsBoundUsingDataSourceID)

  {

  this.RequiresDataBinding = true;

  }

  base.OnDataPropertyChanged();

  }

  /// <summary>

  /// Renders only current items selected by pager

  /// </summary>

  /// <param name="writer"></param>

  protected override void RenderChildren(HtmlTextWriter writer)

  {

  if (!PagingInDataSource && MaximumRows != -1)

  {

  foreach (RepeaterItem item in this.Items)

  {

  if (item.ItemType == ListItemType.Item || item.ItemType == ListItemType.AlternatingItem)

  {

  item.Visible = false;

  if (item.ItemIndex >= (int)ViewState["StartRowIndex"] && item.ItemIndex < ((int)ViewState["StartRowIndex"] + (int)ViewState["MaximumRows"]))

  {

  item.Visible = true;

  }

  }

  else

  {

  item.Visible = true;

  }

  }

  }

  base.RenderChildren(writer);

  }

  /// <summary>

  /// Get Data

  /// </summary>

  /// <returns></returns>

  protected override System.Collections.IEnumerable GetData()

  {

  System.Collections.IEnumerable dataObjects = base.GetData();

  if (dataObjects == null && this.DataSource != null)

  {

  if (this.DataSource is System.Collections.IEnumerable)

  dataObjects = (System.Collections.IEnumerable)this.DataSource;

  else

  dataObjects = ((System.ComponentModel.IListSource)this.DataSource).GetList();

  }

  if (!PagingInDataSource && MaximumRows != -1 && dataObjects != null)

  {

  int i = -1;

  if (dataObjects != null)

  {

  i = 0;

  foreach (object o in dataObjects)

  {

  i++;

  }

  }

  ViewState["TotalRows"] = i;

  if (!IsBoundUsingDataSourceID && PersistentDataSource)

  ViewState["DataSource"] = this.DataSource;

  SetPageProperties(StartRowIndex, MaximumRows, true);

  }

  if (PagingInDataSource && !Page.IsPostBack)

  {

  SetPageProperties(StartRowIndex, MaximumRows, true);

  }

  return dataObjects;

  }

  /// <summary>

  /// Event when pager/repeater have counted total rows

  /// </summary>

  public event System.EventHandler<PageEventArgs> TotalRowCountAvailable;

  /// <summary>

  /// Event when repeater gets the data on postback

  /// </summary>

  public event System.EventHandler<PageEventArgs> FetchingData;

  }

  }

  ASPX页面要做的事情(以我网站的留言板为例):

  首先得把标签注册进来

  

复制代码 代码如下:
<%@ Register Assembly="WYJ.Web.Controls" Namespace="WYJ.Web.Controls" TagPrefix="WYJ" %>

  然后添加我们的Repeater

  

复制代码 代码如下:

  <WYJ:DataPagerRepeater ID="rptLeaveword" runat="server" PersistentDataSource="true">

  <ItemTemplate>

  <div class="leavewordentry">

  <div class="datebox">

  <div class="time">

  <%# ((GeekStudio.ORM.Model.Leaveword)Container.DataItem).Posttime.ToString("HH:mm") %></div>

  <div class="day">

  <%# ((GeekStudio.ORM.Model.Leaveword)Container.DataItem).Posttime.ToString("dd") %>

  </div>

  <div class="month">

  <%# ((GeekStudio.ORM.Model.Leaveword)Container.DataItem).Posttime.ToString("MMM", new CultureInfo("en-US")).ToUpper() %><%# ((GeekStudio.ORM.Model.Leaveword)Container.DataItem).Posttime.ToString(" yyyy") %></div>

  </div>

  <div class="contentbox">

  <h2 class="username">

  <a id="<%# GeekStudio.Common.IdEncryptor.EncodeId(((GeekStudio.ORM.Model.Leaveword)Container.DataItem).Id) %>"

  name="<%# GeekStudio.Common.IdEncryptor.EncodeId(((GeekStudio.ORM.Model.Leaveword)Container.DataItem).Id) %>">

  <%# ((GeekStudio.ORM.Model.Leaveword)Container.DataItem).Username %></a></h2>

  <div class="lvwordcontent">

  <%# ((GeekStudio.ORM.Model.Leaveword)Container.DataItem).Content %>

  </div>

  </div>

  </div>

  </ItemTemplate>

  </WYJ:DataPagerRepeater>

  之后添加.NET自带的DataPager,并自定义一些分页样式

  

复制代码 代码如下:

  <div class="pager">

  <div class="fr">

  共<%=Math.Ceiling((double)DataPager1.TotalRowCount / DataPager1.PageSize)%>页,<%=DataPager1.TotalRowCount%>条记录,每页显示

  <asp:LinkButton ID="lnkbtn10" CssClass="currentpagesize" runat="server" OnClick="lnkbtn10_Click">10</asp:LinkButton>

  <asp:LinkButton ID="lnkbtn20" runat="server" OnClick="lnkbtn20_Click">20</asp:LinkButton>

  <asp:LinkButton ID="lnkbtn30" runat="server" OnClick="lnkbtn30_Click">30</asp:LinkButton>

  </div>

  <asp:DataPager ID="DataPager1" PagedControlID="rptLeaveword" runat="server">

  <Fields>

  <asp:NextPreviousPagerField ShowFirstPageButton="True" ShowNextPageButton="False"

  ShowPreviousPageButton="False" FirstPageText="首页" />

  <asp:NextPreviousPagerField ShowNextPageButton="False" ButtonType="Image" PreviousPageImageUrl="~/Images/icons/pagerprevious.png" />

  <asp:NumericPagerField CurrentPageLabelCssClass="current" />

  <asp:NextPreviousPagerField ShowPreviousPageButton="False" ButtonType="Image" NextPageImageUrl="~/Images/icons/pagernext.png" />

  <asp:NextPreviousPagerField ShowLastPageButton="True" ShowNextPageButton="False"

  ShowPreviousPageButton="False" LastPageText="尾页" />

  </Fields>

  </asp:DataPager>

  </div>

  后台代码:

  分页部分不需要代码。下面发的代码是切换每页显示数量的:

  

复制代码 代码如下:

  protected void lnkbtn10_Click(object sender, EventArgs e)

  {

  DataPager1.PageSize = 10;

  lnkbtn10.CssClass = "currentpagesize";

  lnkbtn20.CssClass = "";

  lnkbtn30.CssClass = "";

  }

  protected void lnkbtn20_Click(object sender, EventArgs e)

  {

  DataPager1.PageSize = 20;

  lnkbtn20.CssClass = "currentpagesize";

  lnkbtn10.CssClass = "";

  lnkbtn30.CssClass = "";

  }

  protected void lnkbtn30_Click(object sender, EventArgs e)

  {

  DataPager1.PageSize = 30;

  lnkbtn30.CssClass = "currentpagesize";

  lnkbtn10.CssClass = "";

  lnkbtn20.CssClass = "";

  }

  二、自定义GridView

  

复制代码 代码如下:

  using System;

  using System.Collections;

  using System.Web.UI.WebControls;

  namespace WYJ.Web.Controls

  {

  /// <summary>

  /// DataPagerGridView is a custom control that implements GrieView and IPageableItemContainer

  /// </summary>

  public class DataPagerGridView : GridView, IPageableItemContainer

  {

  public DataPagerGridView()

  : base()

  {

  PagerSettings.Visible = false;

  }

  /// <summary>

  /// TotalRowCountAvailable event key

  /// </summary>

  private static readonly object EventTotalRowCountAvailable = new object();

  /// <summary>

  /// Call base control's CreateChildControls method and determine the number of rows in the source

  /// then fire off the event with the derived data and then we return the original result.

  /// </summary>

  /// <param name="dataSource"></param>

  /// <param name="dataBinding"></param>

  /// <returns></returns>

  protected override int CreateChildControls(IEnumerable dataSource, bool dataBinding)

  {

  int rows = base.CreateChildControls(dataSource, dataBinding);

  // if the paging feature is enabled, determine the total number of rows in the datasource

  if (this.AllowPaging)

  {

  // if we are databinding, use the number of rows that were created, otherwise cast the datasource to an Collection and use that as the count

  int totalRowCount = dataBinding ? rows : ((ICollection)dataSource).Count;

  // raise the row count available event

  IPageableItemContainer pageableItemContainer = this as IPageableItemContainer;

  this.OnTotalRowCountAvailable(new PageEventArgs(pageableItemContainer.StartRowIndex, pageableItemContainer.MaximumRows, totalRowCount));

  // make sure the top and bottom pager rows are not visible

  if (this.TopPagerRow != null)

  this.TopPagerRow.Visible = false;

  if (this.BottomPagerRow != null)

  this.BottomPagerRow.Visible = false;

  }

  return rows;

  }

  /// <summary>

  /// Set the control with appropriate parameters and bind to right chunk of data.

  /// </summary>

  /// <param name="startRowIndex"></param>

  /// <param name="maximumRows"></param>

  /// <param name="databind"></param>

  void IPageableItemContainer.SetPageProperties(int startRowIndex, int maximumRows, bool databind)

  {

  int newPageIndex = (startRowIndex / maximumRows);

  this.PageSize = maximumRows;

  if (this.PageIndex != newPageIndex)

  {

  bool isCanceled = false;

  if (databind)

  {

  // create the event arguments and raise the event

  GridViewPageEventArgs args = new GridViewPageEventArgs(newPageIndex);

  this.OnPageIndexChanging(args);

  isCanceled = args.Cancel;

  newPageIndex = args.NewPageIndex;

  }

  // if the event wasn't cancelled change the paging values

  if (!isCanceled)

  {

  this.PageIndex = newPageIndex;

  if (databind)

  this.OnPageIndexChanged(EventArgs.Empty);

  }

  if (databind)

  this.RequiresDataBinding = true;

  }

  }

  /// <summary>

  /// IPageableItemContainer's StartRowIndex = PageSize * PageIndex properties

  /// </summary>

  int IPageableItemContainer.StartRowIndex

  {

  get { return this.PageSize * this.PageIndex; }

  }

  /// <summary>

  /// IPageableItemContainer's MaximumRows = PageSize property

  /// </summary>

  int IPageableItemContainer.MaximumRows

  {

  get { return this.PageSize; }

  }

  /// <summary>

  ///

  /// </summary>

  event EventHandler<PageEventArgs> IPageableItemContainer.TotalRowCountAvailable

  {

  add { base.Events.AddHandler(DataPagerGridView.EventTotalRowCountAvailable, value); }

  remove { base.Events.RemoveHandler(DataPagerGridView.EventTotalRowCountAvailable, value); }

  }

  /// <summary>

  ///

  /// </summary>

  /// <param name="e"></param>

  protected virtual void OnTotalRowCountAvailable(PageEventArgs e)

  {

  EventHandler<PageEventArgs> handler = (EventHandler<PageEventArgs>)base.Events[DataPagerGridView.EventTotalRowCountAvailable];

  if (handler != null)

  {

  handler(this, e);

  }

  }

  }

  }

  用法与Repeater类似,不多发了~