分頁和排序報告資料 (C#)
在在線應用程式中顯示數據時,分頁和排序是兩個非常常見的功能。 在本教學課程中,我們將先探討如何將排序和分頁新增至報表,然後在未來的教學課程中加以建置。
簡介
在在線應用程式中顯示數據時,分頁和排序是兩個非常常見的功能。 例如,在在線書籍存放區搜尋 ASP.NET 書籍時,可能會有數百份這類書籍,但列出搜尋結果的報表只會列出每頁 10 個相符專案。 此外,結果可以依標題、價格、頁面計數、作者名稱等排序。 雖然過去 23 個教學課程已檢查如何建置各種報表,包括允許新增、編輯和刪除數據的介面,但我們並未查看如何排序數據,以及我們所看到的唯一分頁範例與 DetailsView 和 FormView 控件。
在本教學課程中,我們將瞭解如何將排序和分頁新增至報表,只要勾選幾個複選框即可完成。 可惜的是,這種簡化實作有其缺點,排序介面會留下一些需要,而且分頁例程不是針對透過大型結果集有效率地分頁而設計。 未來的教學課程將探索如何克服現用分頁和排序解決方案的限制。
步驟 1:新增分頁和排序教學課程網頁
開始本教學課程之前,讓我們先花一點時間新增本教學課程和下三個教學課程所需的 ASP.NET 頁面。 首先,在名為 PagingAndSorting
的專案中建立新的資料夾。 接下來,將下列五個 ASP.NET 頁新增至此資料夾,讓所有頁面都設定為使用主版頁面 Site.master
:
Default.aspx
SimplePagingSorting.aspx
EfficientPaging.aspx
SortParameter.aspx
CustomSortingUI.aspx
圖 1:建立 PagingAndSorting 資料夾並新增教學課程 ASP.NET 頁面
接下來,開啟Default.aspx
頁面,然後將 [使用者控件] 從UserControls
資料夾拖曳SectionLevelTutorialListing.ascx
到 [設計] 介面。 我們在 主版頁面和網站導覽 教學課程中建立的這個使用者控件會列舉網站地圖,並在點符清單中的目前區段中顯示這些教學課程。
圖 2:將 SectionLevelTutorialListing.ascx 使用者控件新增至 Default.aspx
為了讓項目符號清單顯示我們將建立的分頁和排序教學課程,我們需要將它們新增至網站地圖。 開啟檔案 Web.sitemap
,並在 [編輯]、[插入] 和 [刪除網站地圖] 節點標記之後新增下列標記:
<siteMapNode title="Paging and Sorting" url="~/PagingAndSorting/Default.aspx"
description="Samples of Reports that Provide Paging and Sorting Capabilities">
<siteMapNode url="~/PagingAndSorting/SimplePagingSorting.aspx"
title="Simple Paging & Sorting Examples"
description="Examines how to add simple paging and sorting support." />
<siteMapNode url="~/PagingAndSorting/EfficientPaging.aspx"
title="Efficiently Paging Through Large Result Sets"
description="Learn how to efficiently page through large result sets." />
<siteMapNode url="~/PagingAndSorting/SortParameter.aspx"
title="Sorting Data at the BLL or DAL"
description="Illustrates how to perform sorting logic in the Business Logic
Layer or Data Access Layer." />
<siteMapNode url="~/PagingAndSorting/CustomSortingUI.aspx"
title="Customizing the Sorting User Interface"
description="Learn how to customize and improve the sorting user interface." />
</siteMapNode>
圖 3:更新網站地圖以包含新的 ASP.NET 頁面
步驟 2:在 GridView 中顯示產品資訊
在實際實作分頁和排序功能之前,讓我們先建立列出產品信息的標準不可排序、不可分頁的 GridView。 這是我們在本教學課程系列之前多次完成的工作,因此這些步驟應該很熟悉。 首先,SimplePagingSorting.aspx
開啟頁面並將 GridView 控制件從 [工具箱] 拖曳至 Designer,並將其 ID
屬性設定為 Products
。 接下來,建立使用 ProductsBLL 類別 s GetProducts()
方法來傳回所有產品資訊的新 ObjectDataSource。
圖 4:使用 GetProducts () 方法擷取所有產品的相關信息
由於此報表是只讀報表,因此不需要將 ObjectDataSource s Insert()
、 Update()
或 Delete()
方法對應至對應的 ProductsBLL
方法;因此,請從 UPDATE、INSERT 和 DELETE 索引卷標的下拉式清單中選擇 ([無) ]。
圖 5:在 [更新]、[插入] 和 [刪除] 索引卷標的 ([Drop-Down 列表中,選擇 [無]) 選項
接下來,讓我們自定義 GridView 的欄位,以便只顯示產品名稱、供應商、類別、價格和已停止的狀態。 此外,您可以隨意進行任何字段層級的格式設定變更,例如調整 HeaderText
屬性或將價格格式化為貨幣。 這些變更之後,您的 GridView 宣告式標記看起來應該類似下列內容:
<asp:GridView ID="Products" runat="server" AutoGenerateColumns="False"
DataKeyNames="ProductID" DataSourceID="ObjectDataSource1"
EnableViewState="False">
<Columns>
<asp:BoundField DataField="ProductName" HeaderText="Product"
SortExpression="ProductName" />
<asp:BoundField DataField="CategoryName" HeaderText="Category"
ReadOnly="True" SortExpression="CategoryName" />
<asp:BoundField DataField="SupplierName" HeaderText="Supplier"
ReadOnly="True" SortExpression="SupplierName" />
<asp:BoundField DataField="UnitPrice" HeaderText="Price"
SortExpression="UnitPrice" DataFormatString="{0:C}"
HtmlEncode="False" />
<asp:CheckBoxField DataField="Discontinued" HeaderText="Discontinued"
SortExpression="Discontinued" />
</Columns>
</asp:GridView>
圖 6 顯示我們到目前為止透過瀏覽器檢視時的進度。 請注意,頁面會列出一個畫面中的所有產品,其中顯示每個產品的名稱、類別、供應商、價格和已停止的狀態。
圖 6:每個產品都會列示 (按兩下以檢視完整大小的影像)
步驟 3:新增分頁支援
列出一個畫面上 的所有 產品,可能會導致使用者瀏覽數據的資訊多載。 為了協助讓結果更容易管理,我們可以將數據分成較小的數據頁,並讓使用者一次逐步執行一個頁面的數據。 若要完成此作業,請直接核取 GridView 智慧標記中的 [啟用分頁] 複選框, (這會將 GridView s AllowPaging
屬性 設定為 true
) 。
圖 7:核取 [啟用分頁] 複選框以新增分頁支援 (按兩下即可檢視大小完整的映射)
啟用分頁會限制每個頁面顯示的記錄數目,並將 分頁介面 新增至 GridView。 圖 7 所示的預設分頁介面是一系列的頁碼,可讓使用者快速從一頁的數據流覽到另一個頁面。 此分頁介面看起來應該很熟悉,如同我們在過去教學課程中將分頁支援新增至 DetailsView 和 FormView 控件時所見。
DetailsView 和 FormView 控件只會顯示每個頁面的單一記錄。 不過,GridView 會參考其 PageSize
屬性 ,以判斷每個頁面要顯示的記錄數目, (此屬性預設為 10) 。
您可以使用下列屬性來自定義此 GridView、DetailsView 和 FormView 分頁介面:
PagerStyle
表示分頁介面的樣式資訊;可以指定 、ForeColor
、CssClass
、HorizontalAlign
等設定BackColor
。PagerSettings
包含屬性的 Bevy,可自定義分頁介面的功能;PageButtonCount
表示在分頁介面中顯示的數值頁碼數目上限, (預設值為 10) ;Mode
屬性 會指出分頁介面的運作方式,並可設定為:NextPrevious
顯示 [下一頁] 和 [上一頁] 按鈕,讓使用者一次向前或向後一頁NextPreviousFirstLast
除了 [下一頁] 和 [上一頁] 按鈕之外,也包含 [第一個] 和 [最後一個] 按鈕,讓用戶能夠快速移至數據的第一頁或最後一頁Numeric
顯示一系列的頁碼,允許使用者立即跳到任何頁面NumericFirstLast
除了頁碼之外,還包含 [第一頁] 和 [最後一頁] 按鈕,允許使用者快速移至數據的第一頁或最後一頁;只有在所有數值頁碼都無法容納時,才會顯示 [第一個/最後一頁] 按鈕
此外,GridView、DetailsView 和 FormView 都提供 PageIndex
和 PageCount
屬性,這表示正在檢視的目前頁面,以及分別檢視的數據頁總數。 屬性 PageIndex
是從 0 開始編製索引,這表示在檢視第一頁數據 PageIndex
時會等於 0。 PageCount
另一方面,會開始計算為 1,這表示 PageIndex
僅限於介於 0 和 PageCount - 1
之間的值。
讓我們花點時間改善 GridView 分頁介面的默認外觀。 具體來說,讓我們讓分頁介面靠右對齊淺灰色背景。 讓我們在名為 PagerRowStyle
中建立 CSS 類別Styles.css
,然後透過 Theme 指派 PagerStyle
s CssClass
屬性,而不是直接透過 GridView 屬性PagerStyle
設定這些屬性。 首先,開啟 Styles.css
並新增下列 CSS 類別定義:
.PagerRowStyle
{
background-color: #ddd;
text-align: right;
}
接下來,開啟GridView.skin
資料夾內資料夾中的App_Themes
檔案DataWebControls
。 如我們在 主版頁面和網站導覽 教學課程中所討論,面板檔案可用來指定 Web 控件的預設屬性值。 因此,請增強現有的設定,以包含 將 s CssClass
屬性設定PagerStyle
為 PagerRowStyle
。 此外,讓我們設定分頁介面,以使用 NumericFirstLast
分頁介面顯示最多五個數值頁面按鈕。
<asp:GridView runat="server" CssClass="DataWebControlStyle">
<AlternatingRowStyle CssClass="AlternatingRowStyle" />
<RowStyle CssClass="RowStyle" />
<HeaderStyle CssClass="HeaderStyle" />
<FooterStyle CssClass="FooterStyle" />
<SelectedRowStyle CssClass="SelectedRowStyle" />
<PagerStyle CssClass="PagerRowStyle" />
<PagerSettings Mode="NumericFirstLast" PageButtonCount="5" />
</asp:GridView>
分頁用戶體驗
圖 8 顯示瀏覽瀏覽器時瀏覽網頁的 GridView s Enable Paging 複選框,並已透過GridView.skin
檔案進行和PagerStyle
PagerSettings
設定。 請注意,只會顯示 10 筆記錄,而分頁介面表示我們正在檢視數據的第一頁。
圖 8:啟用分頁時,一次只會顯示一個記錄子集, (按兩下即可檢視大小完整的影像)
當使用者按兩下分頁介面中的其中一個頁碼時,回傳會後置,而頁面會重載,其中顯示所要求的頁面記錄。 圖 9 顯示選擇檢視最後一頁數據之後的結果。 請注意,最終頁面只有一筆記錄;這是因為總共有 81 筆記錄,因此每頁有 10 筆記錄,加上一個單一記錄的頁面。
圖 9:按兩下頁碼會導致回傳,並顯示適當的記錄子集, (按兩下即可檢視大小完整的影像)
分頁 Server-Side 工作流程
當使用者按下列伺服器端工作流程:
- GridView s (或 DetailsView 或 FormView)
PageIndexChanging
事件引發 - ObjectDataSource 會從 BLL 重新要求 所有數據 ;GridView s
PageIndex
和PageSize
屬性值是用來判斷從 BLL 傳回哪些記錄必須在 GridView 中顯示 - GridView 事件
PageIndexChanged
會引發
在步驟 2 中,ObjectDataSource 會重新要求其數據源中的所有數據。 這個分頁樣式通常稱為預設分頁,因為它是將 屬性true
設定AllowPaging
為 時預設使用的分頁行為。 使用預設分頁時,數據 Web 控件會以貝氏方式擷取每個數據頁面的所有記錄,即使只有一部分記錄實際上會轉譯到傳送至瀏覽器的 HTML 中也一樣。 除非資料庫數據是由 BLL 或 ObjectDataSource 快取,否則預設分頁無法用於足夠大型的結果集或具有許多並行使用者的 Web 應用程式。
在下一個教學課程中,我們將探討如何實 作自定義分頁。 使用自定義分頁,您可以特別指示 ObjectDataSource 只擷取要求之數據頁面所需的精確記錄集。 如您所想像,自定義分頁可大幅提升透過大型結果集分頁的效率。
注意
雖然在分頁到足夠大型的結果集或具有許多同時使用者的網站時,預設分頁並不適合使用,但請注意自定義分頁需要更多變更和努力來實作,而且不像核取複選框 (一樣簡單,就像預設分頁) 一樣簡單。 因此,預設分頁可能是小型、低流量網站或分頁相對小型結果集時的理想選擇,因為實作更容易且更快速。
例如,如果我們知道資料庫中永遠不會有超過100個產品,則自定義分頁所享有的最小效能可能會因實作所需的工作而位移。 不過,如果我們一天可能會有數千或數千個產品, 但未 實作自定義分頁會大幅降低應用程式的延展性。
步驟 4:自定義分頁體驗
數據 Web 控制項提供許多屬性,可用來增強使用者的分頁體驗。 例如,屬性 PageCount
會指出有多少總頁數,而 PageIndex
屬性則表示目前流覽的頁面,而且可以設定為快速將使用者移至特定頁面。 為了說明如何使用這些屬性來改善使用者的分頁體驗,讓我們將標籤 Web 控件新增至我們的頁面,告知使用者目前瀏覽的頁面,以及可讓他們快速跳至任何指定頁面的 DropDownList 控件。
首先,將標籤 Web 控件新增至頁面、將其 ID
屬性設定為 PagingInformation
,並清除其 Text
屬性。 接下來,建立 GridView s DataBound
事件的事件處理程式,並新增下列程式代碼:
protected void Products_DataBound(object sender, EventArgs e)
{
PagingInformation.Text = string.Format("You are viewing page {0} of {1}...",
Products.PageIndex + 1, Products.PageCount);
}
此事件處理程式會將 PagingInformation
Label s Text
屬性指派給訊息,告知使用者目前瀏覽Products.PageIndex + 1
的頁面,而我們新增 1 PageIndex
Products.PageIndex
個頁面的總頁Products.PageCount
數, (從 0) 開始編製索引。 我選擇在事件處理程式中DataBound
指派這個 Label s Text
屬性,而不是事件處理程式,PageIndexChanged
因為DataBound
每次數據系結至 GridView 時都會引發事件,而PageIndexChanged
事件處理程式只會在頁面索引變更時引發。 當 GridView 最初系結在第一頁瀏覽的數據時, PageIndexChanging
事件不會引發 (,而 DataBound
事件會) 。
此外,用戶現在會顯示一則訊息,指出他們瀏覽的頁面,以及有多少數據總數。
圖 10:[目前頁碼] 和 [總頁數] 會顯示 (按兩下即可檢視大小完整的影像)
除了標籤之外,讓我們新增DropDownList控件,以列出 GridView 中目前已選取的頁面編號。 這裡的概念是使用者只要從DropDownList 選取新的頁面索引,即可快速從目前頁面跳到另一個頁面。 首先,將DropDownList新增至 Designer,並將其 屬性設定ID
為 PageList
,並從其智慧標記中檢查 [啟用 AutoPostBack] 選項。
接下來,返回 DataBound
事件處理程式,並新增下列程序代碼:
// Clear out all of the items in the DropDownList
PageList.Items.Clear();
// Add a ListItem for each page
for (int i = 0; i < Products.PageCount; i++)
{
// Add the new ListItem
ListItem pageListItem = new ListItem(string.Concat("Page ", i + 1), i.ToString());
PageList.Items.Add(pageListItem);
// select the current item, if needed
if (i == Products.PageIndex)
pageListItem.Selected = true;
}
此程式代碼會從清除DropDownList中的 PageList
項目開始。 這似乎是多餘的,因為一個使用者不會預期頁面數目變更,但其他使用者可能會同時使用系統,從數據表新增或移除記錄 Products
。 這類插入或刪除可能會改變數據頁數。
接下來,我們需要再次建立頁碼,並讓對應至默認選取的目前 GridView PageIndex
。 我們會使用從 0 到 PageCount - 1
的循環來完成這項作業,並在目前的反覆專案索引等於 GridView s PageIndex
屬性時,在每個反覆專案中加入新的 ,ListItem
並將其Selected
屬性設定為 true。
最後,我們需要為DropDownList s SelectedIndexChanged
事件建立事件處理程式,每當使用者從清單中挑選不同的專案時,就會引發此事件處理程式。 若要建立此事件處理程式,只要按兩下 Designer 中的DropDownList,然後新增下列程式代碼:
protected void PageList_SelectedIndexChanged(object sender, EventArgs e)
{
// Jump to the specified page
Products.PageIndex = Convert.ToInt32(PageList.SelectedValue);
}
如圖 11 所示,只要變更 GridView 的 PageIndex
屬性,數據就會重新系結至 GridView。 在 GridView 的 DataBound
事件處理程式中,已選取適當的 DropDownList ListItem
。
圖 11:選取第 6 頁 Drop-Down 清單專案時,用戶會自動進入第六頁 (按鍵即可檢視大小完整的影像)
步驟 5:新增 Bi-Directional 排序支援
新增雙向排序支援就像新增分頁支援一樣簡單,只要從 GridView 的智慧標記 (檢查 [啟用排序] 選項,即可將 GridView s AllowSorting
屬性 設定為 true
) 。 這會將 GridView 字段的每個標頭轉譯為 LinkButtons,當按兩下時,會造成回傳,並傳回依按一下的數據行以遞增順序排序的數據。 再次按一下相同的標頭 LinkButton 會以遞減順序重新排序數據。
注意
如果您使用自定義數據存取層,而不是具類型的數據集,則 GridView 智慧標記中可能沒有 [啟用排序] 選項。 只有系結至原生支援排序之數據源的 GridViews 才能使用此複選框。 Typed DataSet 提供現成的排序支援,因為 ADO.NET DataTable 提供Sort
方法,在叫用時,使用指定的準則排序 DataTable s DataRows。
如果您的 DAL 未傳回原生支援排序的物件,您必須將 ObjectDataSource 設定為將排序資訊傳遞至商業規則層,以便排序數據或讓 DAL 排序的數據。 我們將在未來的教學課程中探索如何在商業規則和數據存取層排序數據。
排序 LinkButtons 會轉譯為 HTML 超連結,其目前色彩 (藍色表示未檢視的連結,而瀏覽連結的深紅色) 與標題列的背景色彩衝突。 相反地,讓我們讓所有標頭數據列連結都以白色顯示,不論它們是否已流覽過。 將下列內容新增至 Styles.css
類別即可完成此作業:
.HeaderStyle a, .HeaderStyle a:visited
{
color: White;
}
此語法表示在使用 HeaderStyle 類別的項目內顯示這些超連結時,使用白色文字。
新增此 CSS 之後,瀏覽頁面時,您的畫面看起來應該類似圖 12。 特別是,圖 12 會顯示按兩下 [價格] 欄位標頭連結之後的結果。
圖 12:結果已依遞增順序排序 UnitPrice (按兩下即可檢視大小完整的影像)
檢查排序工作流程
所有 GridView 字段 BoundField、CheckBoxField、TemplateField 等都有 SortExpression
屬性,表示當按兩下該字段排序標頭連結時,應該用來排序數據的表達式。 GridView 也有 SortExpression
屬性。 按兩下排序標頭LinkButton時,GridView 會將該欄位 SortExpression
的值指派給其 SortExpression
屬性。 接下來,會從 ObjectDataSource 重新擷取數據,並根據 GridView s SortExpression
屬性排序。 下列清單詳述使用者排序 GridView 中數據時所轉譯的步驟順序:
- GridView s Sorting 事件 會引發
- GridView s
SortExpression
屬性 會設定為SortExpression
已按下排序標頭 LinkButton 之欄位的 - ObjectDataSource 會從 BLL 重新擷取所有數據,然後使用 GridView s 排序數據
SortExpression
- GridView s
PageIndex
屬性會重設為 0,這表示排序使用者時會傳回數據的第一頁, (假設已實作分頁支援) - GridView 事件
Sorted
會引發
如同預設分頁,預設排序選項會重新擷取 BLL 中的所有 記錄。 在沒有分頁的情況下使用排序,或使用具有默認分頁的排序時,沒有任何方法可以規避此效能點擊, (快取資料庫數據) 。 不過,如未來教學課程中所見,在使用自定義分頁時,可以有效率地排序數據。
透過 GridView 智慧標記中的下拉式清單將 ObjectDataSource 系結至 GridView 時,每個 GridView 欄位都會自動 SortExpression
將其屬性指派給 類別中的數據 ProductsRow
欄位名稱。 例如, ProductName
BoundField s SortExpression
設定 ProductName
為 ,如下列宣告式標記所示:
<asp:BoundField DataField="ProductName" HeaderText="Product"
SortExpression="ProductName" />
您可以設定欄位,使其無法排序,方法是清除其 SortExpression
屬性, (將它指派給空字串) 。 為了說明這一點,假設我們不想讓客戶依價格排序產品。 UnitPrice
BoundField s SortExpression
屬性可以從宣告式標記或透過 [字段] 對話框移除, (按兩下 GridView 智慧標記) 中的 [編輯資料行] 連結即可存取。
圖 13:結果已以遞增順序依 UnitPrice 排序
一旦已移除 UnitPrice
BoundField 的屬性SortExpression
,標頭就會轉譯為文字,而不是鏈接,進而防止使用者依價格排序數據。
圖 14:藉由移除 SortExpression 屬性,用戶無法再依價格排序產品 (按兩下即可檢視大小完整的影像)
以程序設計方式排序 GridView
您也可以使用 GridView 的 Sort
方法來以程式設計方式排序 GridView 的內容。 只要傳入 SortExpression
值以與 SortDirection
(Ascending
或 Descending
) 一起排序,GridView 的數據將會重新排序。
假設我們關閉排序的原因 UnitPrice
,是因為我們擔心客戶只會購買最低價格的產品。 不過,我們想要鼓勵他們購買最昂貴的產品,因此我們希望他們能夠依價格排序產品,但只從最昂貴的價格到最低價格。
若要完成此作業,請將按鈕 Web 控制項新增至頁面,將其 ID
屬性 SortPriceDescending
設定為 ,並將其 Text
屬性設定為 [依價格排序]。 接下來,按兩下 Designer中的Button控件,以建立Button s Click
事件的事件處理程式。 將下列程式代碼新增至此事件處理程式:
protected void SortPriceDescending_Click(object sender, EventArgs e)
{
// Sort by UnitPrice in descending order
Products.Sort("UnitPrice", SortDirection.Descending);
}
按下此按鈕會將用戶傳回第一頁,其中包含依價格排序的產品,從最昂貴到成本最低的 (請參閱圖 15) 。
圖 15:按兩下 [按鈕],將產品從最昂貴到最低 (按兩下即可檢視大小完整的影像)
摘要
在本教學課程中,我們已瞭解如何實作默認分頁和排序功能,這兩者都如同核取複選框一樣簡單! 當使用者排序或分頁數據時,類似的工作流程會展開:
- 回傳後置
- 數據 Web 控制件的預先層級事件會引發 (
PageIndexChanging
或Sorting
) - ObjectDataSource 會重新擷取所有數據
- 數據 Web 控制件的後置事件會引發 (
PageIndexChanged
或Sorted
)
雖然實作基本分頁和排序很輕鬆,但必須努力利用更有效率的自定義分頁,或進一步增強分頁或排序介面。 未來的教學課程將探索這些主題。
快樂的程序設計!
關於作者
Scott Mitchell 是七份 ASP/ASP.NET 書籍的作者,以及 自 1998 年以來與 Microsoft Web 技術合作的 4GuysFromRolla.com 作者。 Scott 是獨立顧問、訓練員和作者。 他的最新書籍是 Sams 在 24 小時內自行 ASP.NET 2.0。 您可以透過mitchell@4GuysFromRolla.com部落格來連線到 ,您可以在 找到http://ScottOnWriting.NET。
意見反應
https://aka.ms/ContentUserFeedback。
即將登場:在 2024 年,我們將逐步淘汰 GitHub 問題作為內容的意見反應機制,並將它取代為新的意見反應系統。 如需詳細資訊,請參閱:提交並檢視相關的意見反應