Scott Mitchell 的ASP.NET 2.0数据教程之四十四::DataList和Repeater数据分页
原文?| 下載本教程中的編碼例子 | 下載本教程的PDF版
導(dǎo)言
分頁和排序是顯示數(shù)據(jù)時經(jīng)常用到的功能。比如,在一個在線書店里搜索關(guān)于ASP.NET 的書的時候,可能結(jié)果會是成百上千,而每頁只列出十條。而且結(jié)果可以根據(jù)title(書名),price(價格),page count(頁數(shù)),author name(作者)等來排序。我們在分頁和排序報表數(shù)據(jù) 里已經(jīng)討論過, GridView, DetailsView, 和FormView 都有內(nèi)置的分頁功能,僅僅只需要勾一個checkbox就可以開啟。GridView 還支持內(nèi)置的排序。
不幸的是,DataList 和Repeater 都沒有提供內(nèi)置的分頁和排序功能。本章我們將學習如何在DataList 和Repeater 里添加分頁和排序的支持。我們需要創(chuàng)建分頁界面,顯示正確的頁的記錄,并在postback過程中記下瀏覽的頁。雖然這會比GridView, DetailsView, 和FormView里花費更多的時間和寫更多的代碼,但是也提供了更多的可擴展性。
注意:本章集中精力討論分頁,下章我們將學習排序。
第一步: 添加分頁和排序的教程頁
首先添加本章和下一章需要的頁。創(chuàng)建一個名為PagingSortingDataListRepeater的文件夾,然后添加下面的5個頁,記得全部選擇Site.master。
- Default.aspx
- Paging.aspx
- Sorting.aspx
- SortingWithDefaultPaging.aspx
- SortingWithCustomPaging.aspx
圖 1: 創(chuàng)建頁
然后打開Default.aspx頁,從UserControls文件夾里拖一個SectionLevelTutorialListing.ascx用戶控件進來。這個用戶控件我們已經(jīng)用了很多次了。見母板頁和站點導(dǎo)航? 。
圖 2: 添加用戶控件
為了將排序和分頁的教程列出來,我們需要將他們添加到site map(站點地圖)里。打開Web.sitemap文件,將下面的標記語言添加到“Editing and Deleting with the DataList”()的節(jié)點后面:
| XML | |
| 12345678910111213141516171819202122232425 | <siteMapNodeurl="~/PagingSortingDataListRepeater/Default.aspx"title="Paging and Sorting with the DataList and Repeater"description="Paging and Sorting the Data in the DataList and Repeater Controls"><siteMapNodeurl="~/PagingSortingDataListRepeater/Paging.aspx"title="Paging"description="Learn how to page through the data shownin the DataList and Repeater controls." /><siteMapNodeurl="~/PagingSortingDataListRepeater/Sorting.aspx"title="Sorting"description="Sort the data displayed in a DataList orRepeater control." /><siteMapNodeurl="~/PagingSortingDataListRepeater/SortingWithDefaultPaging.aspx"title="Sorting with Default Paging"description="Create a DataList or Repeater control that is paged usingdefault paging and can be sorted." /><siteMapNodeurl="~/PagingSortingDataListRepeater/SortingWithCustomPaging.aspx"title="Sorting with Custom Paging"description="Learn how to sort the data displayed in a DataList orRepeater control that uses custom paging." /></siteMapNode> |
圖 3:?更新 Site Map
回顧一下分頁
在前面我們學習了如何使用GridView, DetailsView, FormView 來分頁。這三個控件都提供了一種稱為默認分頁的功能,僅僅只需要從智能標簽里勾上“Enable Paging”(開啟分頁)即可。在使用默認分頁時,每次請求數(shù)據(jù) – 無論是第一頁還是其它頁–GridView, DetailsView, 和FormView 都會重新請求所有的數(shù)據(jù)。然后根據(jù)請求的頁索引和每頁顯示的記錄數(shù)來顯示特定頁的數(shù)據(jù),而忽略其它數(shù)據(jù)(即雖然被請求但未顯示的數(shù)據(jù))。我們在分頁和排序報表數(shù)據(jù) 里已經(jīng)詳細的討論過默認分頁了。
默認分頁由于每次都請求所有的數(shù)據(jù),因此在大數(shù)據(jù)量的情況下并不合適。例如,想象一下每頁顯示10條數(shù)據(jù),總共有有50,000條。每次用戶瀏覽一頁時,都要從數(shù)據(jù)庫請求50,000條數(shù)據(jù),而其中只有10條會被顯示。
自定義分頁使用每次只返回請求的數(shù)據(jù),從而解決了默認分頁的性能問題。當使用自定義分頁時,我們需要寫有效的返回正確的記錄的SQL語句。我們在里學習了用SQL Server2005的ROW_NUMBER() keyword 來創(chuàng)建這樣的語句。
在DataList或Repeater里使用默認分頁,我們可以使用PagedDataSource class來包裝ProductsDataTable里需要分頁的內(nèi)容。PagedDataSource類有一個可以賦給任何枚舉類型對象的DataSource屬性,和PageSize (每頁顯示的記錄數(shù))and CurrentPageIndex (當前頁的索引)。一旦設(shè)置了這些屬性,PagedDataSource就可以作為任何數(shù)據(jù)控件的數(shù)據(jù)源。PagedDataSource根據(jù)PageSize和CurrentPageIndex來返回合適的記錄。圖4描述了PagedDataSource類的功能。
圖 4: PagedDataSource使用可分頁的界面包裝枚舉對象
PagedDataSource對象可以在BLL里直接創(chuàng)建和配置,并通過ObjectDataSource綁定到DataList或Repeater。或者也可以在ASP.NET 頁的后臺代碼里直接做這些。如果使用后一種方法,我們就不能使用ObjectDataSource而應(yīng)該直接編程將分頁數(shù)據(jù)綁定到DataList或Repeater。
PagedDataSource對象也有支持自定義分頁的屬性。但是在這里我們將不討論它,因為我們在ProductsBLL類里已經(jīng)有一個可以精確的返回需要顯示的記錄的方法。
本章我們將學習如何通過在ProductsBLL類里添加一個返回合適的PagedDataSource對象的方法來實現(xiàn)默認分頁。下章我們再討論自定義分頁。
第二步: 在BLL里添加默認的分頁方法
ProductsBLL類里現(xiàn)在有一個返回所有product的方法–GetProducts()–和一個返回特定子集的方法–GetProductsPaged(startRowIndex,maximumRows)。當使用默認分頁時,GridView, DetailsView, FormView 使用GetProducts()方法獲取所有的product,但是在內(nèi)部使用PagedDataSource來顯示正確的記錄子集。在DataList和Repeater里實現(xiàn)同樣的功能,我們可以在BLL里創(chuàng)建一個模擬這種行為的方法。
在ProductsBLL里添加一個帶兩個整型參數(shù)的方法,名為GetProductsAsPagedDataSource:
- pageIndex – 顯示的頁的索引,從0開始
- pageSize – 每頁顯示的記錄數(shù).
GetProductsAsPagedDataSource首先從GetProducts()里獲取所有的記錄。然后創(chuàng)建一個PagedDataSource對象,將CurrentPageIndex和PageSize屬性設(shè)置為傳進來的參數(shù),pageIndex和pageSize。方法的最后返回這個配置過的PagedDataSource。
| C# | |
| 12345678910111213141516 | [System.ComponentModel.DataObjectMethodAttribute(System.ComponentModel.DataObjectMethodType.Select, false)]public PagedDataSource GetProductsAsPagedDataSource(int pageIndex, int pageSize){// Get ALL of the productsNorthwind.ProductsDataTable products = GetProducts();// Limit the results through a PagedDataSourcePagedDataSource pagedData = new PagedDataSource();pagedData.DataSource = products.Rows;pagedData.AllowPaging = true;pagedData.CurrentPageIndex = pageIndex;pagedData.PageSize = pageSize;return pagedData;} |
第三步: 在DataList里使用默認分頁顯示Product
完成GetProductsAsPagedDataSource方法后,我們現(xiàn)在來創(chuàng)建一個提供默認分頁的DataList或Repeater。打開PagingSortingDataListRepeater文件夾下的Paging.aspx頁,拖一個DataList進來,將ID設(shè)為ProductsDefaultPaging。通過智能標簽創(chuàng)建一個名為ProductsDefaultPagingDataSource的ObjectDataSource并用GetProductsAsPagedDataSource方法配置它。
圖 5: 創(chuàng)建并配置ObjectDataSource
在UPDATE, INSERT, DELETE 標簽的下拉列表里都選擇“(None)”.
圖 6: 在UPDATE, INSERT, DELETE 標簽的下拉里選擇“(None)”
?
因為GetProductsAsPagedDataSource方法需要兩個參數(shù),因此向?qū)崾疚覀冞x擇參數(shù)源。
page index和page size的值必須在postback過程中記下來。它們可以存在view state,querystring,session里或用其它技術(shù)來記錄。本章我們使用querystring。
分別使用querystring字段“pageIndex” 和“pageSize”來配置pageIndex和pageSize。見圖7。由于用戶第一次瀏覽頁的時候沒有querystring,因此還需要設(shè)置這兩個參數(shù)的默認值。將pageIndex的默認值設(shè)為0(表示顯示第一頁數(shù)據(jù)),將pageSize的默認值設(shè)為4。
圖 7: 配置參數(shù)
配置完ObjectDataSource后,Visual Studio自動為DataList創(chuàng)建一個ItemTemplate。修改它讓它只顯示product的name,category和supplier。將DataList的RepeatColumns屬性設(shè)為2,Width設(shè)為“100%”, ItemStyle的Width設(shè)為 “50%”. 這樣的設(shè)置會為兩列提供相同的間距。
完成這些后DataList和ObjectDataSource的標記語言看起來應(yīng)該如下:
| ASP.NET | |
| 12345678910111213141516171819202122232425262728 | <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> |
注意:由于這里我們不實現(xiàn)任何更新或刪除的功能,你可以禁用DataList的view state來減少頁面的大小。
第一次瀏覽頁的時候,querystring里沒有提供pageIndex 和pageSize的值,因此將使用默認的0和4。見圖8。DataList將顯示4條product記錄。
圖 8: 顯示4條Product
由于還沒有分頁的界面,因此用戶現(xiàn)在還不能直接導(dǎo)航到第二頁。我們將在第四步里創(chuàng)建分頁界面。現(xiàn)在我們只能直接在querystring里指定分頁的參數(shù)來進行分頁。例如,我們可以將地址從Paging.aspx改為Paging.aspx?pageIndex=2,然后回車,來瀏覽第二頁。這樣就可以看到第二頁的數(shù)據(jù)了,見圖9。
圖 9: 顯示第二頁數(shù)據(jù)
第四步: 創(chuàng)建分頁界面
有很多不同的完成分頁界面的方法。GridView, DetailsView, FormView 提供了4種不同的界面:
- Next, Previous(后一頁,前一頁) – 用戶可以瀏覽上一頁或下一頁.
- Next, Previous, First(第一頁), Last (最后一頁)– 除了上面的功能,這個還包含第一頁和最后一頁。
- Numeric (數(shù)字)–在分頁界面上列出頁數(shù),用戶可以隨意的選擇一個頁 .
- Numeric, First, Last – 在上一個功能的基礎(chǔ)上增加了第一頁和最后一頁.
對DataList 和Repeater而言,我們需要決定它的分頁界面并實現(xiàn)它。這其中包含了需要創(chuàng)建web控件和當特定頁的button被點時顯示請求的頁。另外某些分頁界面的控件可能需要禁用。例如,當使用Next, Previous, First, Last這個模式來顯示時,如果瀏覽第一頁數(shù)據(jù),那么第一頁和前一頁的button應(yīng)該被禁用。
本章我們使用 Next, Previous, First, Last界面。添加4個button,并將ID分別設(shè)為FirstPage,PrevPage,NextPage和LastPage。將Text設(shè)為“<< First”, “< Prev”, “Next >”, “Last >>”.
| ASP.NET | |
| 1234 | <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創(chuàng)建一個Click事件處理。呆會我們將添加代碼來顯示請求的頁。
記下分頁的總記錄數(shù)
不管選擇哪種分頁界面,我們都需要計算和記下分頁的總記錄數(shù)。總的行數(shù)(和page size)來決定總的頁數(shù),它決定了那些分頁界面的控件需要增加或啟用。在我們創(chuàng)建的Next, Previous, First, Last 界面里,page count(頁數(shù))在兩種情況下需要被用到:
- ?判斷我們是否在瀏覽最后一頁,這種情況下Next 和Last buttons 需要禁用。
- ?如果用戶點了Last button我們需要將它轉(zhuǎn)到最后一頁,它的索引等于page count減1。
page count通過總行數(shù)除以page size(頁數(shù))來計算得到。例如我們要分頁79條記錄,每頁顯示4條,那么page count為20(79/4)。如果我們使用數(shù)字分頁界面,就可以通過這個信息來決定要顯示多少個數(shù)字頁的button。如果分頁界面只包含Next 和Last buttons,可以通過page?count來什么時候禁用Next 和Last buttons。
如果分頁界面包含Last button(最后一頁),我們需要在postback過程中記下分頁的總記錄數(shù),這樣在點Last button的時候我們可以獲得最后一頁的索引。為了方便實現(xiàn)這個,我們在ASP.NET頁的后臺代碼里創(chuàng)建一個TotalRowCount屬性來將這個值保存到view state里。
| C# | |
| 123456789101112131415 | private int TotalRowCount{get{object o = ViewState["TotalRowCount"];if (o == null)return -1;elsereturn (int)o;}set{ViewState["TotalRowCount"] = value;}} |
除了TotalRowCount外,還需要為page index,page size和page count創(chuàng)建頁面級的只讀屬性來方便讀取。
| C# | |
| 1234567891011121314151617181920212223242526272829 | private int PageIndex{get{if (!string.IsNullOrEmpty(Request.QueryString["pageIndex"]))return Convert.ToInt32(Request.QueryString["pageIndex"]);elsereturn 0;}}private int PageSize{get{if (!string.IsNullOrEmpty(Request.QueryString["pageSize"]))return Convert.ToInt32(Request.QueryString["pageSize"]);elsereturn 4;}}private int PageCount{get{return (TotalRowCount / PageSize) + 1;}} |
獲取分頁的總記錄數(shù)
從ObjectDataSource的Select()方法返回一個PagedDataSource對象包含所有的product記錄,即使只有一部分會在DataList里顯示。PagedDataSource的Count property 返回將在DataList里顯示的項的數(shù)目。DataSourceCount property 返回PagedDataSource里的所有項的的總數(shù)目。因此我們需要將ASP.NET頁的TotalRowCount屬性賦值為PagedDataSource的DataSourceCount。
我們?yōu)镺bjectDataSource的Selectd事件創(chuàng)建一個event handler來完成這些。在Selectd的event handler里我們獲取ObjectDataSource的Select()方法的返回值–在這種情況下是PagedDataSource。
| C# | |
| 12345678910 | protected void ProductsDefaultPagingDataSource_Selected(object sender, ObjectDataSourceStatusEventArgs e){// Reference the PagedDataSource bound to the DataListPagedDataSource pagedData = (PagedDataSource)e.ReturnValue;// Remember the total number of records being paged through // across postbacksTotalRowCount = pagedData.DataSourceCount;} |
顯示請求的頁的數(shù)據(jù)
當用戶點分頁界面上的button時,我們需要顯示請求的頁的數(shù)據(jù)。由于分頁的參數(shù)在querystring里指定,因此使用Response.Redirect(url)來讓用戶重新請求帶合適分頁參數(shù)的Paging.aspx頁。例如,顯示第二頁的數(shù)據(jù),我們將用戶重定向到Paging.aspx?pageIndex=1。
創(chuàng)建一個RedirectUser(sendUserToPageIndex)方法來重定向用戶到Paging.aspx?pageIndex=sendUserToPageIndex。然后在四個按鈕的Click事件處理里調(diào)用這個方法。在FirstPageClick里調(diào)用RedirectUser(0),在PrevPageClick里調(diào)用RedirectUser(PageIndex-1)。
?
| C# | |
| 123456789101112131415161718192021222324252627282930 | protected void FirstPage_Click(object sender, EventArgs e){// Send the user to the first pageRedirectUser(0);}protected void PrevPage_Click(object sender, EventArgs e){// Send the user to the previous pageRedirectUser(PageIndex - 1);}protected void NextPage_Click(object sender, EventArgs e){// Send the user to the next pageRedirectUser(PageIndex + 1);}protected void LastPage_Click(object sender, EventArgs e){// Send the user to the last pageRedirectUser(PageCount - 1);}private void RedirectUser(int sendUserToPageIndex){// Send the user to the requested pageResponse.Redirect(string.Format("Paging.aspx?pageIndex={0}&pageSize={1}",sendUserToPageIndex, PageSize));} |
完成Click事件處理后,DataList的記錄現(xiàn)在可以通過button來分頁了,你可以測試一下。
禁用分頁控件
現(xiàn)在無論瀏覽哪頁四個按鈕都是可用的。然而我們在瀏覽第一頁時需要禁用 First 和Previous buttons ,在瀏覽最后一頁時需要禁用Next 和Last buttons。通過ObjectDataSource的Select()方法返回的PagedDataSource對象有幾個屬性– IsFirstPage?和 IsLastPage –通過它們可以判斷用戶瀏覽的是否是第一或最后一頁數(shù)據(jù)。
添加下面的代碼到ObjectDataSource的Selected事件處理里:
| C# | |
| 123456 | // Configure the paging interface based on the data in the PagedDataSourceFirstPage.Enabled = !pagedData.IsFirstPage;PrevPage.Enabled = !pagedData.IsFirstPage;NextPage.Enabled = !pagedData.IsLastPage;LastPage.Enabled = !pagedData.IsLastPage; |
添加完后,當瀏覽第一頁時,First 和Previous buttons 將被禁用。當瀏覽最后一頁時,Next?和 ?Last buttons 將被禁用。
我們最后來實現(xiàn)在分頁界面里通知用戶他們當前是瀏覽的哪頁和一共有多少頁。添加一個Label控件并將ID設(shè)為CurrentPageNumber。在ObjectDataSource的Selected事件處理中設(shè)置它的Text屬性,讓它顯示當前瀏覽的頁(PageIndex+1)和總頁數(shù)(PageCount)。
| C# | |
| 123 | // Display the current page being viewed...CurrentPageNumber.Text = string.Format("You are viewing page {0} of {1}...",PageIndex + 1, PageCount); |
圖10是第一次瀏覽Paging.aspx頁的樣子。由于querystring是空的,因此DataList默認顯示最開始的4條product。First 和Previous buttons 被禁用。點Next 會顯示下面的4條記錄(見圖11),而First 和Previous buttons 同時被啟用了。
圖 10: 第一頁數(shù)據(jù)
圖 11: 第二頁數(shù)據(jù)
注意:分頁界面可以進一步改善,比如增加允許用戶來指定每頁顯示多少記錄。例如添加一個DropDownList列出page size的選項,比如5, 10, 25, 50, 和ALL。用戶選擇了page size后會重定向到Paging.aspx?pageIndex=0&pageSize=selectedPageSize。我將這個作為練習留給讀者自己完成。?
使用自定義分頁
DataList使用沒有效率的默認分頁技術(shù)。當大數(shù)據(jù)量時,我們需要使用自定義分頁。雖然實現(xiàn)的細節(jié)有所不同,但是分頁里的概念和默認分頁是一樣的。默認分頁時,使用ProductsBLL類的GetProductsPaged方法(而不是GetProductsAsPagedDataSource)。正如在大數(shù)據(jù)量時提高分頁的效率 里討論的那樣,GetProductsPaged需要傳入開始行的索引和行的最大數(shù)目。這些參數(shù)可以通過默認分頁里使用的querystring里的pageIndex和pageSize參數(shù)來保存。
由于自定義分頁里沒有PagedDataSource,所以需要其它技術(shù)來決定總記錄數(shù)和判斷我們是否顯示第一或最后一頁數(shù)據(jù)。ProductsBLL類的TotalNumberOfProducts()方法返回roduct的總記錄數(shù)。而為了判斷是否瀏覽的是第一頁數(shù)據(jù),我們需要檢查開始行的索引–如果是0,則表示在瀏覽第一頁。如果開始行的索引加上最大的行數(shù)大于或等于總記錄數(shù)則表示在最后一頁
我們將在下章詳細的討論如何實現(xiàn)自定義分頁。
總結(jié)
DataList和Repeater都沒有提供象GridView, DetailsView, FormView 那樣的分頁的支持,這樣的功能需要我們來實現(xiàn)。最簡單的實現(xiàn)方法是使用默認分頁,將所有的product都包裝到PagedDataSource里,然后綁定PagedDataSource到DataList或Repeater。本章我們在ProductsBLL類里添加了GetProductsAsPagedDataSource方法,它返回PagedDataSource。ProductsBLL類已經(jīng)包含了自定義分頁需要的方法– GetProductsPaged和TotalNumberOfProducts。
不管是自定義方法里獲取精確的記錄還是默認方法里獲取所有記錄,我們都需要手動添加分頁界面。本章我們創(chuàng)建的是包含4個button控件的Next, Previous, First, Last interface 。當然還添加了一個顯示當前頁和總頁數(shù)的Label控件。
下章將學習如何為DataList和Repeater提供排序功能。我們也會創(chuàng)建一個既支持分頁又支持排序的DataList(和使用默認和自定義分頁的例子)
祝編程愉快!
轉(zhuǎn)載于:https://www.cnblogs.com/Fernando/archive/2007/11/08/953225.html
總結(jié)
以上是生活随笔為你收集整理的Scott Mitchell 的ASP.NET 2.0数据教程之四十四::DataList和Repeater数据分页的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 进行有效编辑的七种习惯
- 下一篇: 必然的宿命,绚然的《暗花》