DataList和Repeater数据分页

导言

  分页和排序是显示数据时经常用到的功能。比如,在一个在线书店里搜索关于ASP.net 的书的时候,可能结果会是成百上千,而每页只列出十条。而且结果可以根据title(书名),price(价格),page count(页数),author name(作者)等来排序。我们在分页和排序报表数据 里已经讨论过, GridView, DetailsView, 和FormView 都有内置的分页功能,仅仅只需要勾一个checkbox就可以开启。GridView 还支持内置的排序。

  不幸的是,DataList 和Repeater 都没有提供内置的分页和排序功能。本章我们将学习如何在DataList 和Repeater 里添加分页和排序的支持。我们需要创建分页界面,显示正确的页的记录,并在postback过程中记下浏览的页。虽然这会比GridView, DetailsView, 和FormView里花费更多的时间和写更多的代码,但是也提供了更多的可扩展性。

  注意:本章集中精力讨论分页,下章我们将学习排序。

  第一步: 添加分页和排序的教程页

  首先添加本章和下一章需要的页。创建一个名为PagingSortingDataListRepeater的文件夹,然后添加下面的5个页,记得全部选择Site.master。

  Default.aspx

  Paging.aspx

  Sorting.aspx

  SortingWithDefaultPaging.aspx

  SortingWithCustomPaging.aspx

  图 1: 创建页

  然后打开Default.aspx页,从UserControls文件夹里拖一个SectionLevelTutorialListing.ascx用户控件进来。这个用户控件我们已经用了很多次了。见母板页和站点导航 。

  图 2: 添加用户控件

  为了将排序和分页的教程列出来,我们需要将他们添加到site map(站点地图)里。打开Web.sitemap文件,将下面的标记语言添加到“Editing and Deleting with the DataList”()的节点后面:

  XML

<siteMapNode
      url="~/PagingSortingDataListRepeater/Default.ASPx"
      title="Paging and Sorting with the DataList and Repeater"
      description="Paging and Sorting the Data in the DataList and Repeater Controls">
      <siteMapNode
      url="~/PagingSortingDataListRepeater/Paging.aspx"
      title="Paging"
      description="Learn how to page through the data shown
      in the DataList and Repeater controls." />
      <siteMapNode
      url="~/PagingSortingDataListRepeater/Sorting.aspx"
      title="Sorting"
      description="Sort the data displayed in a DataList or
      Repeater control." />
      <siteMapNode
      url="~/PagingSortingDataListRepeater/SortingWithDefaultPaging.aspx"
      title="Sorting with Default Paging"
      description="Create a DataList or Repeater control that is paged using
      default paging and can be sorted." />
      <siteMapNode
      url="~/PagingSortingDataListRepeater/SortingWithCustomPaging.aspx"
      title="Sorting with Custom Paging"
      description="Learn how to sort the data displayed in a DataList or
      Repeater control that uses custom paging." />
      </siteMapNode>

 

  图 3:更新 Site Map

  回顾一下分页

  在前面我们学习了如何使用GridView, DetailsView, FormView 来分页。这三个控件都提供了一种称为默认分页的功能,仅仅只需要从智能标签里勾上“Enable Paging”(开启分页)即可。在使用默认分页时,每次请求数据 – 无论是第一页还是其它页–GridView, DetailsView, 和FormView 都会重新请求所有的数据。然后根据请求的页索引和每页显示的记录数来显示特定页的数据,而忽略其它数据(即虽然被请求但未显示的数据)。我们在分页和排序报表数据 里已经详细的讨论过默认分页了。

  默认分页由于每次都请求所有的数据,因此在大数据量的情况下并不合适。例如,想象一下每页显示10条数据,总共有有50,000条。每次用户浏览一页时,都要从数据库请求50,000条数据,而其中只有10条会被显示。

  自定义分页使用每次只返回请求的数据,从而解决了默认分页的性能问题。当使用自定义分页时,我们需要写有效的返回正确的记录的SQL语句。我们在里学习了用SQL Server2005的ROW_NUMBER() keyword 来创建这样的语句。

  在DataList或Repeater里使用默认分页,我们可以使用PagedDataSource class来包装ProductsDataTable里需要分页的内容。PagedDataSource类有一个可以赋给任何枚举类型对象的DataSource属性,和PageSize (每页显示的记录数)and CurrentPageIndex (当前页的索引)。一旦设置了这些属性,PagedDataSource就可以作为任何数据控件的数据源。PagedDataSource根据PageSize和CurrentPageIndex来返回合适的记录。图4描述了PagedDataSource类的功能

 

  图 4: PagedDataSource使用可分页的界面包装枚举对象

  PagedDataSource对象可以在BLL里直接创建和配置,并通过ObjectDataSource绑定到DataList或Repeater。或者也可以在ASP.net 页的后台代码里直接做这些。如果使用后一种方法,我们就不能使用ObjectDataSource而应该直接编程将分页数据绑定到DataList或Repeater。

  PagedDataSource对象也有支持自定义分页的属性。但是在这里我们将不讨论它,因为我们在ProductsBLL类里已经有一个可以精确的返回需要显示的记录的方法。

  本章我们将学习如何通过在ProductsBLL类里添加一个返回合适的PagedDataSource对象的方法来实现默认分页。下章我们再讨论自定义分页。

  第二步: 在BLL里添加默认的分页方法

  ProductsBLL类里现在有一个返回所有product的方法–GetProducts()–和一个返回特定子集的方法–GetProductsPaged(startRowIndex,maximumRows)。当使用默认分页时,GridView, DetailsView, FormView 使用GetProducts()方法获取所有的product,但是在内部使用PagedDataSource来显示正确的记录子集。在DataList和Repeater里实现同样的功能,我们可以在BLL里创建一个模拟这种行为的方法。

  在ProductsBLL里添加一个带两个整型参数的方法,名为GetProductsAsPagedDataSource:

  pageIndex – 显示的页的索引,从0开始

  pageSize – 每页显示的记录数.

  GetProductsAsPagedDataSource首先从GetProducts()里获取所有的记录。然后创建一个PagedDataSource对象,将CurrentPageIndex和PageSize属性设置为传进来的参数,pageIndex和pageSize。方法的最后返回这个配置过的PagedDataSource

 

C#

[System.ComponentModel.DataObjectMethodAttribute
      (System.ComponentModel.DataObjectMethodType.Select, false)]
      public PagedDataSource GetProductsASPagedDataSource(int pageIndex, int pageSize)
      {
      // Get ALL of the products
      Northwind.ProductsDataTable products = GetProducts();
      // Limit the results through a PagedDataSource
      PagedDataSource pagedData = new PagedDataSource();
      pagedData.DataSource = products.Rows;
      pagedData.AllowPaging = true;
      pagedData.CurrentPageIndex = pageIndex;
      pagedData.PageSize = pageSize;
      return pagedData;
      }

  第三步: 在DataList里使用默认分页显示Product

  完成GetProductsAsPagedDataSource方法后,我们现在来创建一个提供默认分页的DataList或Repeater。打开PagingSortingDataListRepeater文件夹下的Paging.aspx页,拖一个DataList进来,将ID设为ProductsDefaultPaging。通过智能标签创建一个名为ProductsDefaultPagingDataSource的ObjectDataSource并用GetProductsAsPagedDataSource方法配置它。

  图 5: 创建并配置ObjectDataSource

  在UPDATE, INSERT, DELETE 标签的下拉列表里都选择“(None)”.

 

  图 6: 在UPDATE, INSERT, DELETE 标签的下拉里选择“(None)”

  因为GetProductsASPagedDataSource方法需要两个参数,因此向导会提示我们选择参数源。

  page index和page size的值必须在postback过程中记下来。它们可以存在view state,querystring,session里或用其它技术来记录。本章我们使用querystring。

  分别使用querystring字段“pageIndex” 和“pageSize”来配置pageIndex和pageSize。见图7。由于用户第一次浏览页的时候没有querystring,因此还需要设置这两个参数的默认值。将pageIndex的默认值设为0(表示显示第一页数据),将pageSize的默认值设为4。

  图 7: 配置参数

  配置完ObjectDataSource后,Visual Studio自动为DataList创建一个ItemTemplate。修改它让它只显示product的name,category和supplier。将DataList的RepeatColumns属性设为2,Width设为“100%”, ItemStyle的Width设为 “50%”. 这样的设置会为两列提供相同的间距。

  完成这些后DataList和ObjectDataSource的标记语言看起来应该如下:

  ASP.NET

<asp:DataList ID="ProductsDefaultPaging" runat="server" Width="100%"
      DataKeyField="ProductID" DataSourceID="ProductsDefaultPagingDataSource"
      RepeatColumns="2" EnableViewState="False">
      <ItemTemplate>
      <h4><asp:Label ID="ProductNameLabel" runat="server"
      Text='<%# Eval("ProductName") %>'></asp:Label></h4>
      Category:
      <asp:Label ID="CategoryNameLabel" runat="server"
      Text='<%# Eval("CategoryName") %>'></asp:Label><br />
      Supplier:
      <asp:Label ID="SupplierNameLabel" runat="server"
      Text='<%# Eval("SupplierName") %>'></asp:Label><br />
      <br />
      <br />
      </ItemTemplate>
      <ItemStyle Width="50%" />
      </asp:DataList>
      <asp:ObjectDataSource ID="ProductsDefaultPagingDataSource" runat="server"
      OldValuesParameterFormatString="original_{0}" TypeName="ProductsBLL"
      SelectMethod="GetProductsAsPagedDataSource">
      <SelectParameters>
      <asp:QueryStringParameter DefaultValue="0" Name="pageIndex"
      QueryStringField="pageIndex" Type="Int32" />
      <asp:QueryStringParameter DefaultValue="4" Name="pageSize"
      QueryStringField="pageSize" Type="Int32" />
      </SelectParameters>
      </asp:ObjectDataSource>

注意:由于这里我们不实现任何更新或删除的功能,你可以禁用DataList的view state来减少页面的大小。

  第一次浏览页的时候,querystring里没有提供pageIndex 和pageSize的值,因此将使用默认的0和4。见图8。DataList将显示4条product记录。

  图 8: 显示4条Product

  由于还没有分页的界面,因此用户现在还不能直接导航到第二页。我们将在第四步里创建分页界面。现在我们只能直接在querystring里指定分页的参数来进行分页。例如,我们可以将地址从Paging.ASPx改为Paging.aspx?pageIndex=2,然后回车,来浏览第二页。这样就可以看到第二页的数据了,见图9。

  图 9: 显示第二页数据

  第四步: 创建分页界面

  有很多不同的完成分页界面的方法。GridView, DetailsView, FormView 提供了4种不同的界面:

  Next, Previous(后一页,前一页) – 用户可以浏览上一页或下一页.

  Next, Previous, First(第一页), Last (最后一页)– 除了上面的功能,这个还包含第一页和最后一页。

  Numeric (数字)–在分页界面上列出页数,用户可以随意的选择一个页 .

  Numeric, First, Last – 在上一个功能的基础上增加了第一页和最后一页.

  对DataList 和Repeater而言,我们需要决定它的分页界面并实现它。这其中包含了需要创建Web控件和当特定页的button被点时显示请求的页。另外某些分页界面的控件可能需要禁用。例如,当使用Next, Previous, First, Last这个模式来显示时,如果浏览第一页数据,那么第一页和前一页的button应该被禁用。

本章我们使用 Next, Previous, First, Last界面。添加4个button,并将ID分别设为FirstPage,PrevPage,NextPage和LastPage。将Text设为“<< First”, “< Prev”, “Next >”, “Last >>”.

  ASP.net

<asp:Button runat="server" ID="FirstPage" Text="<< First" />
      <asp:Button runat="server" ID="PrevPage" Text="< Prev" />
      <asp:Button runat="server" ID="NextPage" Text="Next >" />
      <asp:Button runat="server" ID="LastPage" Text="Last >>" />

  然后为每个button创建一个Click事件处理。呆会我们将添加代码来显示请求的页。

  记下分页的总记录数

  不管选择哪种分页界面,我们都需要计算和记下分页的总记录数。总的行数(和page size)来决定总的页数,它决定了那些分页界面的控件需要增加或启用。在我们创建的Next, Previous, First, Last 界面里,page count(页数)在两种情况下需要被用到:

  判断我们是否在浏览最后一页,这种情况下Next 和Last buttons 需要禁用。

  如果用户点了Last button我们需要将它转到最后一页,它的索引等于page count减1。

  page count通过总行数除以page size(页数)来计算得到。例如我们要分页79条记录,每页显示4条,那么page count为20(79/4)。如果我们使用数字分页界面,就可以通过这个信息来决定要显示多少个数字页的button。如果分页界面只包含Next 和Last buttons,可以通过pagecount来什么时候禁用Next 和Last buttons。

如果分页界面包含Last button(最后一页),我们需要在postback过程中记下分页的总记录数,这样在点Last button的时候我们可以获得最后一页的索引。为了方便实现这个,我们在ASP.net页的后台代码里创建一个TotalRowCount属性来将这个值保存到view state里。

  C#

private int TotalRowCount
      {
      get
      {
      object o = ViewState["TotalRowCount"];
      if (o == null)
      return -1;
      else
      return (int)o;
      }
      set
      {
      ViewState["TotalRowCount"] = value;
      }
      }

  除了TotalRowCount外,还需要为page index,page size和page count创建页面级的只读属性来方便读取。

  C#

private int PageIndex
      {
      get
      {
      if (!string.IsNullOrEmpty(Request.QueryString["pageIndex"]))
      return Convert.ToInt32(Request.QueryString["pageIndex"]);
      else
      return 0;
      }
      }
      private int PageSize
      {
      get
      {
      if (!string.IsNullOrEmpty(Request.QueryString["pageSize"]))
      return Convert.ToInt32(Request.QueryString["pageSize"]);
      else
      return 4;
      }
      }
      private int PageCount
      {
      get
      {
      return (TotalRowCount / PageSize) + 1;
      }
      }

获取分页的总记录数

  从ObjectDataSource的Select()方法返回一个PagedDataSource对象包含所有的product记录,即使只有一部分会在DataList里显示。PagedDataSource的Count property 返回将在DataList里显示的项的数目。DataSourceCount property 返回PagedDataSource里的所有项的的总数目。因此我们需要将ASP.net页的TotalRowCount属性赋值为PagedDataSource的DataSourceCount。

  我们为ObjectDataSource的Selectd事件创建一个event handler来完成这些。在Selectd的event handler里我们获取ObjectDataSource的Select()方法的返回值–在这种情况下是PagedDataSource。

  C#

protected void ProductsDefaultPagingDataSource_Selected
      (object sender, ObjectDataSourceStatusEventArgs e)
      {
      // Reference the PagedDataSource bound to the DataList
      PagedDataSource pagedData = (PagedDataSource)e.ReturnValue;
      // Remember the total number of records being paged through
      // across postbacks
      TotalRowCount = pagedData.DataSourceCount;
      }

  显示请求的页的数据

  当用户点分页界面上的button时,我们需要显示请求的页的数据。由于分页的参数在querystring里指定,因此使用Response.Redirect(url)来让用户重新请求带合适分页参数的Paging.aspx页。例如,显示第二页的数据,我们将用户重定向到Paging.aspx?pageIndex=1。

  创建一个RedirectUser(sendUserToPageIndex)方法来重定向用户到Paging.aspx?pageIndex=sendUserToPageIndex。然后在四个按钮的Click事件处理里调用这个方法。在FirstPageClick里调用RedirectUser(0),在PrevPageClick里调用RedirectUser(PageIndex-1)。

你可能感兴趣的:(DataList和Repeater数据分页)