在ASP.NET 2.0中操作数据之四十三:DataList和Repeater数据排序(二)

接着上篇介绍,上篇已经通过DropDownList简单实现了排序的功能,下面让我们看看带有分页的排序该怎么做。

第五步: 为使用默认分页的DataList添加排序的支持

  打开PagingSortingDataListRepeater文件夹里的SortingWithDefaultPaging.aspx和Paging.aspx 页。在Paging.aspx 页里查看源文件。将图8里选择的文本复制下来,然后粘贴到SortingWithDefaultPaging.aspx 页里的<asp:Content> 标签内。


图 8: 复制粘贴代码

  然后将Paging.aspx页后台代码里的属性和方法也粘贴到SortingWithDefaultPaging.aspx页后台代码里。现在浏览SortingWithDefaultPaging.aspx页,它现在应该有和Paging.aspx页一样的外观和功能。

在ProductsBLL 里添加默认的分页和排序方法

  前面一章里我们在ProductsBLL类里创建了一个GetProductsAsPagedDataSource(pageIndex, pageSize)方法,它返回一个PagedDataSource对象。这个对象通过BLL的GetProducts()方法获取所有的product,然而绑定到DataList的只是那些和输入参数pageIndex 和 pageSize 相关的记录。

  本章前面我们已经通过在ObjectDataSource的 Selecting event handler里指定sort expression来添加了排序功能。当ObjectDataSource返回可排序对象时这个方法运转的很好,比如GetProducts()方法返回的ProductsDataTable。然而GetProductsAsPagedDataSource方法返回的PagedDataSource对象并不支持对它内部数据的排序,因此我们需要在将数据放入PagedDataSource前对GetProducts()方法返回的记录进行排序。

  在ProductsBLL类里建一个GetProductsSortedAsPagedDataSource(sortExpression, pageIndex, pageSize)方法。指定GetProducts() 方法返回的ProductsDataTable的default DataTableView的排序属性。

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

  GetProductsSortedAsPagedDataSource方法和前面一章里的GetProductsAsPagedDataSource方法有一点不一样。GetProductsSortedAsPagedDataSource多了一个sortExpression参数,将它的值赋给ProductDataTable的 DefaultView的Sort属性。并将ProductDataTable的DefaultView赋给PagedDataSource对象的DataSource。

  调用 GetProductsSortedAsPagedDataSource 方法并指定输入参数SortExpression的值

  完成这些后,下一步需要提供参数值。SortingWithDefaultPaging.aspx页的ObjectDataSource现在被配置用来调用GetProductsAsPagedDataSource方法并通过两个QueryStringParameters来传递参数,这些参数在SelectParameters集合里已经指定了。这两个QueryStringParameters参数表示GetProductsAsPagedDataSource方法的pageIndex 和 pageSize 参数从querystring里获取。

  修改ObjectDataSource的SelectMethod属性,让它调用GetProductsSortedAsPagedDataSource方法。然后添加一个新的QueryStringParameter来让sortExpression 参数通过querystring的sortExpression字段获取。将QueryStringParameter的默认值设为“ProductName”。

现在ObjectDataSource的声明标记语言看起来应该和下面差不多:

<asp:ObjectDataSource ID="ProductsDefaultPagingDataSource"
 OldValuesParameterFormatString="original_{0}" TypeName="ProductsBLL"
 SelectMethod="GetProductsSortedAsPagedDataSource"
 OnSelected="ProductsDefaultPagingDataSource_Selected" runat="server">
 <SelectParameters>
 <asp:QueryStringParameter DefaultValue="ProductName"
  Name="sortExpression" QueryStringField="sortExpression"
  Type="String" />
 <asp:QueryStringParameter DefaultValue="0" Name="pageIndex"
  QueryStringField="pageIndex" Type="Int32" />
 <asp:QueryStringParameter DefaultValue="4" Name="pageSize"
  QueryStringField="pageSize" Type="Int32" />
 </SelectParameters>
</asp:ObjectDataSource>

  现在SortingWithDefaultPaging.aspx页会按照product name的字母顺序排序。见图9。这是因为GetProductsSortedAsPagedDataSource方法的sortExpression 参数的默认值为“ProductName”。


图 9: 默认的按照 ProductName 排序

  如果你手动添加一个sortExpression querystring字段–比如SortingWithDefaultPaging.aspx?sortExpression=CategoryName –那么结果会以指定的sortExpression来排序。然而在转到另外一个页时这个sortExpression参数并没有包含在querystring里。实际上当点上或者下一页时我们会返回Paging.aspx。而且当前并没有排序界面。用户可以改变数据排序的唯一方法是直接操作querystring。

创建排序界面

  我们首先要修改RedirectUser方法来将用户重定向到SortingWithDefaultPaging.aspx页(而不是Paging.aspx),并将sortExpression的值包含到querystring里。我们还应该添加一个只读的SortExpression属性。这个属性和前面一章里创建的PageIndex 和 PageSize属性相似,在sortExpression querystring字段存在时返回它的值,否则的话使用默认值“ProductName”。

  现在的RedirectUser方法只接收一个参数–显示的页的index。然而可能有些时候我们需要使用排序表达式将用户重定向到特定数据的页。我们将马上来为这个页创建排序界面,它将包含一些button来为指定的列排序。当其中一个button被点击时,我们需要传入合适的排序表达式的值来重定向用户。为了提供这个功能,创建两个RedirectUser方法。第一个接收page的index,第二个接收page index和sort expression(排序表达式)。

private string SortExpression
{
 get
 {
 if (!string.IsNullOrEmpty(Request.QueryString["sortExpression"]))
  return Request.QueryString["sortExpression"];
 else
  return "ProductName";
 }
}
private void RedirectUser(int sendUserToPageIndex)
{
 // Use the SortExpression property to get the sort expression
 // from the querystring
 RedirectUser(sendUserToPageIndex, SortExpression);
}
private void RedirectUser(int sendUserToPageIndex, string sendUserSortingBy)
{
 // Send the user to the requested page with the requested sort expression
 Response.Redirect(string.Format(
 "SortingWithDefaultPaging.aspx?pageIndex={0}&pageSize={1}&sortExpression={2}",
 sendUserToPageIndex, PageSize, sendUserSortingBy));
}

  本章的第一个例子里,我们使用DropDownList来创建了一个排序界面。我们将在这个例子里使用3个button(它们位于DataList上方)–一个表示为ProductName排序,一个为CategoryName,一个为SupplierName。添加三个button并设置它们的ID和Text。

<p>
 <asp:Button runat="server" id="SortByProductName"
 Text="Sort by Product Name" />
 <asp:Button runat="server" id="SortByCategoryName"
 Text="Sort by Category" />
 <asp:Button runat="server" id="SortBySupplierName"
 Text="Sort by Supplier" />
</p>

  然后为每个button创建一个Click event handler。这个事件处理将调用RedirectUser方法,并使用合适的排序表达式将用户返回到第一页。

protected void SortByProductName_Click(object sender, EventArgs e)
{
 // Sort by ProductName
 RedirectUser(0, "ProductName");
}
protected void SortByCategoryName_Click(object sender, EventArgs e)
{
 // Sort by CategoryName
 RedirectUser(0, "CategoryName");
}
protected void SortBySupplierName_Click(object sender, EventArgs e)
{
 // Sort by SupplierName
 RedirectUser(0, "SupplierName");
}

  第一次浏览该页时,数据将按照product name的字母顺序排序(见图9)。点Next button来浏览第二页,然后点“Sort by Category” button。这样将让页返回到第一页,并按照category name来排序,见图10。同样的,点“Sort by Supplier” button会将数据按照supplier排序,并返回到第一页。当数据分页时排序的选择会被记下来。图11是按照category排序并浏览第十三页的样子。


图 10: Products 按照Category排序


图 11: 分页时会记下Sort Expression

第六步: Repeater的自定义分页

  第五步里的DataList示例使用默认的分页技术。当大数据量时,我们需要使用自定义分页。回到Efficiently Paging Through Large Amounts of Data 和 Sorting Custom Paged Data 里,我们学习了默认和自定义这两种分页方式的不同,并在BLL里为自定义分页和对自定义分页数据的排序创建了方法。在这两章里我们在ProductsBLL里添加了下面三个方法:

  GetProductsPaged(startRowIndex, maximumRows) – 返回从startRowIndex开始并不超过maximumRows  的特定记录集。
  GetProductsPagedAndSorted(sortExpression, startRowIndex, maximumRows) – 根据指定的sortExpression  返回特定记录集。
  TotalNumberOfProducts() – 提供Products 表的总记录数。

  这些方法可以用来在DataList或Repeater进行高效的分页并排序。我们首先创建一个支持自定义分页的Repeater。然后再添加排序支持。打开PagingSortingDataListRepeater文件夹下的SortingWithCustomPaging.aspx页,添加一个Repeater,将ID设为Products。从智能标签里创建一个名为ProductsDataSource的ObjectDataSource。使用ProductsBLL类的GetProductsPaged方法来配置它的select标签。


图 12: 配置 ObjectDataSource

  在UPDATE, INSERT, DELETE标签里选择“(None)”,点下一步。现在我们需要为GetProductsPaged方法的startRowIndex 和 maximumRows 参数选择源。实际上这里不需要配置。这两个参数的值会在ObjectDataSource的Selecting event handler里通过Arguments属性来指定,就好象我们在本章的第一个例子里指定sortExpression 一样。因此,在参数源的下拉列表里选择“None”。


图 13:将参数源设为 “None”

  注意:不要将ObjectDataSource的EnablePaging属性设为true。这样会让ObjectDataSource自动的将它的startRowIndex 和 maximumRows 参数包含在SelectMethod的已经存在的参数列表里。EnablePaging属性在将自定义分页数据绑定到GridView, DetailsView, FormView时才有用。由于我们是为DataList 和Repeater手动添加分页支持,因此将它们设为false(默认的),我们将在ASP.NET页里直接实现这些功能。

  最后,定义Repeater的ItemTemplate,让它只显示product'的name, category, supplier。完成这些后,Repeater和ObjectDataSource的声明语言看起来应该和下面差不多:

<asp:Repeater ID="Products" runat="server" DataSourceID="ProductsDataSource"
 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>
</asp:Repeater>
<asp:ObjectDataSource ID="ProductsDataSource" runat="server"
 OldValuesParameterFormatString="original_{0}"
 SelectMethod="GetProductsPaged" TypeName="ProductsBLL">
 <SelectParameters>
 <asp:Parameter Name="startRowIndex" Type="Int32" />
 <asp:Parameter Name="maximumRows" Type="Int32" />
 </SelectParameters>
</asp:ObjectDataSource>

  现在浏览该页,注意没有返回任何记录。这是因为我们还没有指定startRowIndex 和 maximumRows 参数的值。为了指定这些值,为ObjectDataSource的Selecting event创建一个event handler,并将参数值硬编码的设置为0和5。

protected void ProductsDataSource_Selecting
 (object sender, ObjectDataSourceSelectingEventArgs e)
{
 e.InputParameters["startRowIndex"] = 0;
 e.InputParameters["maximumRows"] = 5;
}

现在浏览页面时会显示前5条product记录。


图 14: 显示前5条product

  注意:图14列出的products以product name排序是因为自定义分页使用的GetProductsPaged存储过程返回的结果是以ProductName排序。

  为了让用户可以翻页,我们需要在postback过程中记下start row index 和 maximum rows。在默认分页的例子里我们用querystring来保存这些值。这个例子里我们将使用view state。创建下面两个属性:

private int StartRowIndex
{
 get
 {
 object o = ViewState["StartRowIndex"];
 if (o == null)
  return 0;
 else
  return (int)o;
 }
 set
 {
 ViewState["StartRowIndex"] = value;
 }
}
private int MaximumRows
{
 get
 {
 object o = ViewState["MaximumRows"];
 if (o == null)
  return 5;
 else
  return (int)o;
 }
 set
 {
 ViewState["MaximumRows"] = value;
 }
}

然后更新Selecting event handler的代码,使用StartRowIndex 和 MaximumRows属性代替硬编码的0和5。

e.InputParameters["startRowIndex"] = StartRowIndex;
e.InputParameters["maximumRows"] = MaximumRows;

现在我们的页仍然只显示5条记录。然而完成这些属性后,我们已经可以创建分页界面了。

添加分页界面

  我们还是使用和默认分页例子里一样的First, Previous, Next, Last分页界面,并包含显示当前是哪页和总页数的label。在Repeater下面添加4个button和1一个label。

<p>
 <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 >>" />
</p>
<p>
 <asp:Label runat="server" ID="CurrentPageNumber"></asp:Label>
</p>

  然后为4个button创建Click event handlers。当其中一个button被点时,我们需要修改StartRowIndex并将数据重新绑定到Repeater。First, Previous, 和 Next button的代码都非常简单,但是对Last button来说,我们如何判断最后一页数据的start row index?为了计算出这个index–和判断Next 和 Last button是否应该enabled一样–我们需要知道分页数据的总数。我们可以调用ProductsBLL类的TotalNumberOfProducts()方法来获取这个总数。我们来创建一个只读的属性,名为TotalRowCount,它返回TotalNumberOfProducts()方法的结果。

private int TotalRowCount
{
 get
 {
 // Return the value from the TotalNumberOfProducts() method
 ProductsBLL productsAPI = new ProductsBLL();
 return productsAPI.TotalNumberOfProducts();
 }
}

  有了这个属性后我们现在可以获取最后一页的start row index。它可以通过TotalRowCount除以MaximumRows的结果的整数部分然后乘以MaximumRows来得到。我们现在可以为4个分页界面的button来写Click event handlers。

  最后,在浏览第一页时需要禁用First 和 Previous buttons,在浏览最后一页时要禁用Next 和 Last buttons。在ObjectDataSource的Selecting event handler里添加以下代码:

// Disable the paging interface buttons, if needed
FirstPage.Enabled = StartRowIndex != 0;
PrevPage.Enabled = StartRowIndex != 0;
int LastPageStartRowIndex = ((TotalRowCount - 1) / MaximumRows) * MaximumRows;
NextPage.Enabled = StartRowIndex < LastPageStartRowIndex;
LastPage.Enabled = StartRowIndex < LastPageStartRowIndex;

  完成这些后,浏览该页。见图15。当第一次浏览该页时,First 和 Previous buttons被禁用。点Next会显示第二页的数据。点Last会显示最后一页的数据(见图16和17)。当浏览最后一页时,Next 和 Last buttons被禁用。


图 15: 浏览第一页时 Previous 和 Last Buttons 被禁用


图 16: 第二页数据


图 17: 最后一页

  祝编程快乐!

作者简介

  本系列教程作者 Scott Mitchell,著有六本ASP/ASP.NET方面的书,是4GuysFromRolla.com的创始人,自1998年以来一直应用 微软Web技术。大家可以点击查看全部教程《[翻译]Scott Mitchell 的ASP.NET 2.0数据教程》,希望对大家的学习ASP.NET有所帮助。

(0)

相关推荐

  • 在ASP.NET 2.0中操作数据之四十六:使用SqlDataSource控件检索数据

    导言 到目前为止,我们探讨的教程是由表现层,业务逻辑层和数据访问层构成的层次体系结构.数据访问层和业务逻辑层分别在教程第一和第二章提到.在Displaying Data With the ObjectDataSource 这篇教程里,我们探讨了怎样用ASP.NET 2.0的新控件--ObjectDataSource控件在表现层展示数据. 本教程到目前为止用这种层次结构来处理数据.然而绕过这种体系结构,通过直接把数据查询和业务逻辑放在Web页面上,也可以达到直接在ASP.NET页面上访问,插入,更

  • 在ASP.NET 2.0中操作数据之四十二:DataList和Repeater数据排序(一)

    导言 DataList和Repeater数据分页里我们学习了如何在DataList里添加分页功能.我们在ProductsBLL类里创建了一个名为GetProductsAsPagedDataSource的方法,它返回一个PagedDataSource对象.当绑定到DataList或Repeater时,他们将只显示请求页的数据.这个技术和GridView,DetailsView,FormView的内置分页功能原理差不多. 除了分页外,GridView还提供了内置的排序功能,而DataList和Rep

  • 在ASP.NET 2.0中操作数据之四十七:用SqlDataSource控件插入、更新、删除数据

    导言: 正如在教程概述插入.更新和删除数据里讨论的那样,GridView控件内置更新和删除功能,而DetailsView和FormView控件不仅具有编辑和删除功能,还有插入功能.我们不要写一行代码就可一将这些功能直接应用于一个数据源控件.在这篇教程里,我们指出ObjectDataSource控件最好与GridView, DetailsView和FormView控件一起使用,才更好的实现插入.更新和删除功能.对SqlDataSource控件来说,同样如此! 对ObjectDataSource控件

  • 在ASP.NET 2.0中操作数据之三十九:在DataList的编辑界面里添加验证控件

    导言 到目前为止的讨论编辑DataList的教程里,没有包含任何验证用户的输入,即使是用户非法输入- 遗漏了product的name或者负的price- 会导致异常.在前面一章里我们学习了如何在DataList的UpdateCommand事件处理中添加异常处理代码,以便在出现异常时捕捉它并显示友好的错误信息.然而理想的编辑界面应该包含验证控件,用来在第一时间里阻止用户输入一些非法数据. 本章我们将学习在DataList的EditItemTemplate里添加验证控件从而提供一个更安全的编辑界面,

  • 在ASP.NET 2.0中操作数据之四十四:DataList和Repeater数据排序(三)

    第七步: 在自定义分页的Repeater 里添加排序功能 现在已经完成了自定义分页,我们再来添加排序功能.ProductsBLL类的GetProductsPagedAndSorted方法和GetProductsPaged一样有startRowIndex 和 maximumRows 参数,不一样的是它还多了一个sortExpression 参数.在SortingWithCustomPaging.aspx里使用GetProductsPagedAndSorted方法我们需要: 将ObjectDataS

  • 在ASP.NET 2.0中操作数据之四十五:DataList和Repeater里的自定义Button

    导言 在前面关于DataList 和Repeater 的7章教程里,我们分别创建了只读和可以编辑删除的例子.为了让DataList有编辑和删除的功能,我们在ItemTemplate里添加了一些button,当点击时,引起postback,并根据button的CommandName属性激发相关的事件.例如,添加一个CommandName为"Edit"的button,在postback时会激发EditCommand事件,如果CommandName为"Delete"则激发

  • aspx中的mysql操作类sqldatasource使用示例分享

    复制代码 代码如下: <%@ Page Language="VB" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtmlll/DTD/xhtmlll.dtd"> <script runat="server"> </script> <html xmlns="h

  • ASP.NET2.0数据库入门之SqlDataSource

    当使用SqlDataSource控件选择数据时,可以从两个属性:ConnectionString和SelectCommand开始,如下所示: <asp:SqlDataSource ID="MySourceControlName" Runat="server" ConnectionString="Server=MyServer ; Database=Northwind" SelectCommand=" SELECT Fieldl,

  • 在ASP.NET 2.0中操作数据之四十一:DataList和Repeater数据分页

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

  • 在ASP.NET 2.0中操作数据之四十:自定义DataList编辑界面

    导言 DataList的编辑界面由EditItemTemplate里的标记语言和web控件定义.在目前为止所做的DataList编辑功能的例子里,编辑界面都只包含TextBox.在前面一章里,我们通过添加验证控件来增加了用户体验,提高了可用性. EditItemTemplate可以包含除了TextBox以外的很多控件,比如DropDownList, RadioButtonList, Calendar等.和使用TextBox一样,使用这些控件自定义编辑界面时,步骤如下: 为EditItemTemp

  • SqlDataSource 链接Access 数据

    还的我耗费了好长时间,研究如何用AccessDataSource链接有密码的access数据库,也没有成功. <appSettings/> <connectionStrings> <add name="ConnectionString" connectionString="Provider=Microsoft.Jet.OLEDB.4.0;Data Source=|DataDirectory|\good.mdb;Persist Security I

随机推荐