建立自訂的排序使用者介面 (VB)
顯示已排序數據的完整清單時,藉由引進分隔符數據列來分組相關數據會很有説明。 在本教學課程中,我們將瞭解如何建立這類排序使用者介面。
簡介
當顯示排序數據列中只有少數不同值的已排序數據長清單時,使用者可能會發現難以辨識確切發生差異界限的位置。 例如,資料庫中有81個產品,但只有九個不同的類別選擇 (八個唯一類別加上 NULL
選項) 。 請考慮有興趣檢查屬於[訂用帳戶] 類別下之產品的使用者案例。 從列出單一 GridView 中所有 產品的頁面中,使用者可能會決定最佳選擇是依類別排序結果,這會將所有「檔案」產品群組在一起。 依類別排序之後,使用者接著必須搜尋清單,以尋找群組於何處開始和結束產品。 由於結果依類別名稱依字母順序排序,而尋找「聖地」產品的類別名稱並不困難,但仍需要仔細掃描方格中的項目清單。
為了協助醒目提示排序群組之間的界限,許多網站都會採用使用者介面,在這類群組之間新增分隔符。 如圖 1 所示的分隔符可讓使用者更快速地尋找特定群組並識別其界限,以及確定數據中存在哪些不同群組。
圖 1:每個類別群組都是清楚識別 (按兩下即可檢視大小完整的影像)
在本教學課程中,我們將瞭解如何建立這類排序使用者介面。
步驟 1:建立標準、可排序的 GridView
在探索如何增強 GridView 以提供增強的排序介面之前,讓我們先建立列出產品的標準可排序 GridView。 首先, CustomSortingUI.aspx
開啟資料夾中的頁面 PagingAndSorting
。 將 GridView 新增至頁面、將其 ID
屬性設定為 ProductList
,並將其系結至新的 ObjectDataSource。 設定 ObjectDataSource 以使用 ProductsBLL
類別 s GetProducts()
方法來選取記錄。
接下來,設定 GridView,使其只包含 ProductName
、 CategoryName
、 SupplierName
和 BoundFields 和 UnitPrice
已停止的 CheckBoxField。 最後,將 GridView 設定為支援排序,方法是核取 GridView 智慧標記中的 [啟用排序] 複選框 (,或將其 AllowSorting
屬性設定為 true
) 。 在加入 CustomSortingUI.aspx
頁面之後,宣告式標記看起來應該類似下列內容:
<asp:GridView ID="ProductList" runat="server" AllowSorting="True"
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" DataFormatString="{0:C}"
HeaderText="Price" HtmlEncode="False" SortExpression="UnitPrice" />
<asp:CheckBoxField DataField="Discontinued" HeaderText="Discontinued"
SortExpression="Discontinued" />
</Columns>
</asp:GridView>
<asp:ObjectDataSource ID="ObjectDataSource1" runat="server"
OldValuesParameterFormatString="original_{0}" SelectMethod="GetProducts"
TypeName="ProductsBLL"></asp:ObjectDataSource>
請花一點時間在瀏覽器中檢視到目前為止的進度。 圖 2 顯示可排序的 GridView,其數據依依字母順序排序時。
圖 2:可排序的 GridView 數據依類別排序 (按鍵即可檢視大小完整的影像)
步驟 2:探索新增分隔符數據列的技術
在泛型、可排序的 GridView 完成之後,所有保留專案都是能夠在每個唯一排序群組之前,在 GridView 中新增分隔符數據列。 但如何將這類數據列插入 GridView 中? 基本上,我們需要逐一查看 GridView 的數據列、判斷排序數據行中值之間的差異,然後新增適當的分隔符數據列。 在思考這個問題時,解決方案似乎自然地位於 GridView RowDataBound
事件處理程式的某處。 如我們根據 數據自定義格式化 教學課程中所討論,根據數據列的數據套用數據列層級格式時,通常會使用此事件處理程式。 不過, RowDataBound
事件處理程式不是這裡的解決方案,因為無法以程序設計方式從這個事件處理程式將數據列新增至 GridView。 GridView 的 Rows
集合事實上是唯讀的。
若要將其他數據列新增至 GridView,我們有三個選項:
- 將這些元數據分隔列新增至系結至 GridView 的實際數據
- 在 GridView 系結至數據之後,將其他
TableRow
實例新增至 GridView 控件集合 - 建立可擴充 GridView 控件的自定義伺服器控件,並覆寫負責建構 GridView 結構的方法
如果許多網頁或多個網站都需要這項功能,建立自定義伺服器控件是最佳方法。 不過,這需要相當多的程序代碼,並徹底探索 GridView 內部工作的深度。 因此,我們不會針對本教學課程考慮該選項。
其他兩個選項會將分隔符數據列新增至系結至 GridView 的實際數據,並在其系結後操作 GridView 控件集合 - 以不同方式攻擊問題,並值得討論。
將數據列新增至系結至 GridView 的數據
當 GridView 系結至數據源時,它會為數據源傳回的每個記錄建立 。GridViewRow
因此,我們可以先將分隔符記錄加入數據源,再將其系結至 GridView,以插入所需的分隔符數據列。 圖 3 說明此概念。
圖 3:一種技術涉及將分隔符數據列新增至數據源
我使用引號中的分隔符記錄,因為沒有特殊分隔符記錄;相反地,我們必須將數據源中的特定記錄標示為分隔符,而不是一般數據列。 在我們的範例中,我們會將 實例系結 ProductsDataTable
至 GridView,由 組成 ProductRows
。 我們可以將記錄標示為分隔符數據列,方法是將其 CategoryID
屬性設定為 -1
(,因為這類值通常無法) 存在。
若要利用這項技術,我們需要執行下列步驟:
- 以程序設計方式擷取要系結至 GridView 的數據, (
ProductsDataTable
實例) - 根據 GridView 和
SortExpression
SortDirection
屬性排序數據 - 逐一查看
ProductsRows
中的ProductsDataTable
,尋找排序數據行的差異所在位置 - 在每個群組界限上,將分隔符記錄
ProductsRow
實例插入 DataTable,其中一個實例已設定CategoryID
為-1
(,或決定將記錄標示為分隔符記錄的任何指定,) - 插入分隔符數據列之後,以程序設計方式將數據系結至 GridView
除了這五個步驟之外,我們也需要提供 GridView s RowDataBound
事件的事件處理程式。 在這裡,我們會檢查每個 DataRow
數據列,並判斷它是否為分隔符數據列,其中一個 CategoryID
設定為 -1
。 若是如此,我們可能會想要調整其格式設定,或單元格中顯示的文字 () 。
使用這項技術來插入排序群組界限需要比上述還要多的工作,因為您也需要為 GridView 事件 Sorting
提供事件處理程式,並追蹤 SortExpression
和 SortDirection
值。
在數據系結之後操作 GridView 的控件集合
除了將數據系結至 GridView 之前傳訊數據,我們可以在數據系結至 GridView 之後 新增分隔符數據列。 數據系結的程式會建置 GridView 的控制階層,實際上只是 Table
由一組數據列組成的實例,每一個都是由單元格集合所組成。 具體來說,GridView 控件集合包含 Table
位於其根目錄的物件、 GridViewRow
衍生自 TableRow
系結至 GridView 中 DataSource
每個記錄之類別) 的 (,以及 TableCell
中每個實例中每個 GridViewRow
數據欄位的物件 DataSource
。
若要在每個排序群組之間新增分隔符數據列,我們可以在建立此控件階層之後直接操作此控件階層。 我們可以確信在頁面轉譯時,已建立 GridView 的控件階層。 因此,此方法會 Page
覆寫 類別 s Render
方法,此時 GridView 的最終控件階層會更新為包含所需的分隔符數據列。 圖 4 說明此程式。
圖 4:替代技術會操作 GridView 的控件階層 (按兩下即可檢視大小完整的影像)
在本教學課程中,我們將使用此後者方法來自定義排序用戶體驗。
注意
我在本教學課程中呈現的程序代碼是以 Teemu Keiski 部落格文章中提供的範例為基礎,使用 GridView 排序群組播放 Bit。
步驟 3:將分隔符數據列新增至 GridView 的控件階層
由於我們只想要在其控件階層建立並建立於該頁面流覽的最後一次之後,將分隔符數據列新增至 GridView 控件階層,因此我們想要在頁面生命週期結束時執行這項新增作業,但在實際 GridView 控件階層轉譯為 HTML 之前。 我們可以完成此 Page
作業的最新可能點是類別事件 Render
,我們可以使用下列方法簽章覆寫程式代碼後置類別:
Protected Overrides Sub Render(ByVal writer As HtmlTextWriter)
' Add code to manipulate the GridView control hierarchy
MyBase.Render(writer)
End Sub
Page
當叫用類別的原始Render
方法base.Render(writer)
時,頁面中的每個控件都會轉譯,並根據其控件階層產生標記。 因此,我們必須呼叫 base.Render(writer)
,以便轉譯頁面,並在呼叫 base.Render(writer)
之前操作 GridView 的控件階層,以便在轉譯之前將分隔符數據列新增至 GridView 控件階層。
若要插入排序群組標頭,我們必須先確定使用者已要求排序數據。 根據預設,GridView 的內容不會排序,因此我們不需要輸入任何群組排序標頭。
注意
如果您想要在第一次載入頁面時依特定數據行排序 GridView,請在第一頁上呼叫 GridView 的 Sort
方法,流覽 (,但不會在後續回傳) 。 若要完成這項作業,請在條件式內的事件處理程式中Page_Load
if (!Page.IsPostBack)
新增此呼叫。 如需方法的詳細資訊,請參閱 分頁和排序報表數據 教學 Sort
課程資訊。
假設數據已排序,下一個工作就是判斷數據排序依據的數據行,然後掃描數據列,以尋找該數據行值的差異。 下列程式代碼可確保資料已排序,並尋找已排序數據的數據行:
Protected Overrides Sub Render(ByVal writer As HtmlTextWriter)
' Only add the sorting UI if the GridView is sorted
If Not String.IsNullOrEmpty(ProductList.SortExpression) Then
' Determine the index and HeaderText of the column that
'the data is sorted by
Dim sortColumnIndex As Integer = -1
Dim sortColumnHeaderText As String = String.Empty
For i As Integer = 0 To ProductList.Columns.Count - 1
If ProductList.Columns(i).SortExpression.CompareTo( _
ProductList.SortExpression) = 0 Then
sortColumnIndex = i
sortColumnHeaderText = ProductList.Columns(i).HeaderText
Exit For
End If
Next
' TODO: Scan the rows for differences in the sorted column�s values
End Sub
如果 GridView 尚未排序,則 GridView 的 SortExpression
屬性將不會設定。 因此,只有當這個屬性有一些值時,我們才想要加入分隔符數據列。 如果這樣做,我們接下來必須判斷數據排序依據的數據行索引。 這是透過迴圈查看 GridView 集合Columns
來完成的,搜尋其屬性等於 GridView s SortExpression
屬性的數據行SortExpression
。 除了數據行的索引之外,我們也會擷取 HeaderText
屬性,在顯示分隔符數據列時會使用此屬性。
使用排序數據的數據行索引,最後一個步驟是列舉 GridView 的數據列。 針對每個數據列,我們需要判斷排序的數據行值是否與前一個數據列的排序數據行值不同。 如果是,我們需要將新的 GridViewRow
實例插入控件階層。 這可透過下列程式代碼來完成:
Protected Overrides Sub Render(ByVal writer As HtmlTextWriter)
' Only add the sorting UI if the GridView is sorted
If Not String.IsNullOrEmpty(ProductList.SortExpression) Then
' ... Code for finding the sorted column index removed for brevity ...
' Reference the Table the GridView has been rendered into
Dim gridTable As Table = CType(ProductList.Controls(0), Table)
' Enumerate each TableRow, adding a sorting UI header if
' the sorted value has changed
Dim lastValue As String = String.Empty
For Each gvr As GridViewRow In ProductList.Rows
Dim currentValue As String = gvr.Cells(sortColumnIndex).Text
If lastValue.CompareTo(currentValue) <> 0 Then
' there's been a change in value in the sorted column
Dim rowIndex As Integer = gridTable.Rows.GetRowIndex(gvr)
' Add a new sort header row
Dim sortRow As New GridViewRow(rowIndex, rowIndex, _
DataControlRowType.DataRow, DataControlRowState.Normal)
Dim sortCell As New TableCell()
sortCell.ColumnSpan = ProductList.Columns.Count
sortCell.Text = String.Format("{0}: {1}", _
sortColumnHeaderText, currentValue)
sortCell.CssClass = "SortHeaderRowStyle"
' Add sortCell to sortRow, and sortRow to gridTable
sortRow.Cells.Add(sortCell)
gridTable.Controls.AddAt(rowIndex, sortRow)
' Update lastValue
lastValue = currentValue
End If
Next
End If
MyBase.Render(writer)
End Sub
此程式代碼會以程式設計方式參考 Table
GridView 控件階層根目錄找到的物件,並建立名為 lastValue
的字串變數。 lastValue
用來比較目前數據列的排序數據行值與前一個數據列的值。 接下來,會列舉 GridView 的 Rows
集合,並針對每個數據列,排序數據行的值會儲存在變數中 currentValue
。
注意
若要判斷特定數據列排序數據行的值,我使用儲存格的 Text
屬性。 這適用於 BoundFields,但不適用於 TemplateFields、CheckBoxFields 等等。 我們將稍後探討如何考慮替代 GridView 欄位。
然後會 currentValue
比較和 lastValue
變數。 如果它們不同,我們需要將新的分隔符數據列新增至控制階層。 這可藉由判斷 物件Rows
集合中的 Table
索引GridViewRow
、建立新的 GridViewRow
和 TableCell
實例,然後將 和 GridViewRow
加入TableCell
至控件階層來完成。
請注意,分隔符數據列的 TableCell
長度會格式化,使其跨越 GridView 的整個寬度、使用 SortHeaderRowStyle
CSS 類別進行格式化,並具有其 Text
屬性,讓其同時顯示排序組名 (,例如 Category ) ,以及群組的值 (,例如「) 」。 最後, lastValue
會更新為的值 currentValue
。
用來格式化排序群組標頭數據列 SortHeaderRowStyle
的 CSS 類別必須在檔案中 Styles.css
指定。 請隨意使用任何樣式設定吸引您;我使用了下列專案:
.SortHeaderRowStyle
{
background-color: #c00;
text-align: left;
font-weight: bold;
color: White;
}
使用目前的程式代碼時,排序介面會在依任何 BoundField 排序時新增排序群組標頭 (請參閱圖 5,其中顯示依供貨商排序時) 的螢幕快照。 不過,依任何其他字段類型排序時, (例如 CheckBoxField 或 TemplateField) ,則找不到排序群組標頭 (請參閱圖 6) 。
圖 5:排序依 BoundFields 排序時,排序介面包含排序群組標頭, (按兩下即可檢視大小完整的影像)
圖 6:排序 CheckBoxField 時遺漏排序群組標頭 (按兩下即可檢視大小完整的影像)
依 CheckBoxField 排序時遺漏排序群組標頭的原因是程式代碼目前只 TableCell
使用 s Text
屬性來判斷每個數據列排序數據行的值。 若為 CheckBoxFields,s TableCell
Text
屬性是空字串,而是可透過位於 集合Controls
內的 TableCell
CheckBox Web 控制項取得此值。
若要處理 BoundFields 以外的欄位類型,我們需要增強指派變數以檢查集合中 TableCell
Controls
CheckBox 是否存在的程式代碼currentValue
。 不要使用 currentValue = gvr.Cells(sortColumnIndex).Text
,請將此程式代碼取代為下列專案:
Dim currentValue As String = String.Empty
If gvr.Cells(sortColumnIndex).Controls.Count > 0 Then
If TypeOf gvr.Cells(sortColumnIndex).Controls(0) Is CheckBox Then
If CType(gvr.Cells(sortColumnIndex).Controls(0), CheckBox).Checked Then
currentValue = "Yes"
Else
currentValue = "No"
End If
' ... Add other checks here if using columns with other
' Web controls in them (Calendars, DropDownLists, etc.) ...
End If
Else
currentValue = gvr.Cells(sortColumnIndex).Text
End If
此程式代碼會檢查目前數據列的已排序 TableCell
數據行,以判斷集合中 Controls
是否有任何控件。 如果有,而第一個控件是 CheckBox,則 currentValue
變數會根據 CheckBox 的 Checked
屬性設定為 [是] 或 [否]。 否則,值會取自 TableCell
s Text
屬性。 您可以復寫此邏輯,以處理任何可能存在於 GridView 中的 TemplateFields 排序。
新增上述程式代碼之後,排序群組標頭現在會在依已停止的 CheckBoxField 排序時出現 (請參閱圖 7) 。
圖 7:排序 CheckBoxField 時,現在會出現排序群組標頭 (按兩下即可檢視大小完整的影像)
注意
如果您有具有 NULL
、 SupplierID
或 UnitPrice
欄位資料庫值CategoryID
的產品,則這些值預設會在 GridView 中顯示為空字串,這表示具有值之產品的NULL
分隔符數據列文字會如 Category: (即,類別目錄之後沒有名稱:例如 Category: 一般類別: [類別] ) 。 如果您想要在此處顯示的值,您可以將 BoundFields NullDisplayText
屬性 設定為所要顯示的文字,或者將 指派 currentValue
給分隔符列 s Text
屬性時,可以在 Render 方法中新增條件語句。
摘要
GridView 不包含許多用於自定義排序介面的內建選項。 不過,使用一些低階程序代碼,可以調整 GridView 的控制階層,以建立更自定義的介面。 在本教學課程中,我們已瞭解如何為可排序的 GridView 新增排序群組分隔符數據列,以更輕鬆地識別不同的群組和這些群組界限。 如需自定義排序介面的其他範例,請參閱 Scott Guthrie s A Few ASP.NET 2.0 GridView Sorting Tips and Tricks 部落格文章。
快樂的程序設計!
關於作者
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 問題作為內容的意見反應機制,並將它取代為新的意見反應系統。 如需詳細資訊,請參閱:提交並檢視相關的意見反應