接着上篇介绍,上篇已经通过DropDownList简单实现了排序的功能,下面让我们看看带有分页的排序该怎么做。
第五步: 为使用默认分页的DataList添加排序的支持
打开PagingSortingDataListRepeater文件夹里的SortingWithDefaultPaging.aspx和Paging.aspx 页。在Paging.aspx 页里查看源文件。将图8里选择的文本复制下来,然后粘贴到SortingWithDefaultPaging.aspx 页里的<asp:Content> 标签内。
然后将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”。
如果你手动添加一个sortExpression querystring字段–比如SortingWithDefaultPaging.aspx"htmlcode">
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", 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排序并浏览第十三页的样子。
第六步: 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标签。
在UPDATE, INSERT, DELETE标签里选择“(None)”,点下一步。现在我们需要为GetProductsPaged方法的startRowIndex 和 maximumRows 参数选择源。实际上这里不需要配置。这两个参数的值会在ObjectDataSource的Selecting event handler里通过Arguments属性来指定,就好象我们在本章的第一个例子里指定sortExpression 一样。因此,在参数源的下拉列表里选择“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列出的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 被禁用
祝编程快乐!
作者简介
本系列教程作者 Scott Mitchell,著有六本ASP/ASP.NET方面的书,是4GuysFromRolla.com的创始人,自1998年以来一直应用 微软Web技术。大家可以点击查看全部教程《[翻译]Scott Mitchell 的ASP.NET 2.0数据教程》,希望对大家的学习ASP.NET有所帮助。
免责声明:本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除!