在 GridView 控制項中使用 TemplateFields (VB)
為了提供彈性,GridView 提供使用範本呈現的TemplateField。 範本可以包含靜態 HTML、Web 控制項和數據系結語法的組合。 在本教學課程中,我們將探討如何使用TemplateField,透過 GridView 控件達到更高的自定義程度。
簡介
GridView 是由一組字段所組成,指出要包含在轉譯輸出中的屬性 DataSource
,以及顯示數據的方式。 最簡單的欄位類型是 BoundField,其會將數據值顯示為文字。 其他欄位類型會使用替代 HTML 元素來顯示數據。 例如,CheckBoxField 會轉譯為複選框,其核取狀態取決於指定數據欄位的值;ImageField 會轉譯影像來源以指定的數據欄位為基礎。 可以使用 HyperLinkField 和 ButtonField 字段類型來轉譯狀態相依於基礎數據域值的超連結和按鈕。
雖然 CheckBoxField、ImageField、HyperLinkField 和 ButtonField 字段類型允許數據的替代檢視,但它們仍然對格式設定相當有限。 CheckBoxField 只能顯示單一複選框,而 ImageField 只能顯示單一影像。 如果特定欄位需要根據不同的數據域值顯示某些文字、複選框 和 影像,該怎麼辦? 或者,如果我們想要使用 CheckBox、Image、HyperLink 或 Button 以外的 Web 控件來顯示數據,該怎麼辦? 此外,BoundField 會將其顯示限制為單一數據欄位。 如果我們想要在單一 GridView 數據行中顯示兩個或多個數據域值,該怎麼辦?
為了容納此層級的彈性,GridView 提供使用 範本呈現的TemplateField。 範本可以包含靜態 HTML、Web 控制項和數據系結語法的組合。 此外,TemplateField 有各種不同的範本,可用來自定義不同情況的轉譯。 例如, ItemTemplate
預設會使用 來呈現每個數據列的數據格,但 EditItemTemplate
範本可用來在編輯數據時自定義介面。
在本教學課程中,我們將探討如何使用TemplateField,透過 GridView 控件達到更高的自定義程度。 在 上一個教學課程中, 我們瞭解如何使用 DataBound
和 RowDataBound
事件處理程式,根據基礎數據自定義格式設定。 根據基礎數據自定義格式的另一種方式,是從範本內呼叫格式化方法。 我們也會在本教學課程中查看這項技術。
在本教學課程中,我們將使用TemplateFields來自定義員工清單的外觀。 具體來說,我們會列出所有員工,但會在一個數據行中顯示員工的名字和姓氏、其雇用日期在行事歷控件中,以及一個狀態數據行,指出他們在公司雇用的天數。
圖 1:三個 TemplateFields 用來自定義顯示 (按兩下即可檢視完整大小的影像)
步驟 1:將數據系結至 GridView
在您需要使用TemplateFields自定義外觀的報告案例中,我發現最容易從建立只包含 BoundFields 的 GridView 控件開始,然後視需要新增 TemplateFields 或將現有的 BoundField 轉換成 TemplateFields。 因此,讓我們透過 Designer 將 GridView 新增至頁面,並將它系結至會傳回員工清單的 ObjectDataSource,來開始本教學課程。 這些步驟會為每個員工字段建立具有 BoundFields 的 GridView。
GridViewTemplateField.aspx
開啟頁面,並將 GridView 從 [工具箱] 拖曳至 Designer。 從 GridView 的智慧標記選擇新增 ObjectDataSource 控件,以叫 EmployeesBLL
用類別的 GetEmployees()
方法。
圖 2:新增可叫用 GetEmployees()
方法的 ObjectDataSource 控件, (Click 以檢視大小完整的影像)
以這種方式系結 GridView 會自動為每個員工屬性新增 BoundField:EmployeeID
、、 Title
LastName
ReportsTo
FirstName
HireDate
和 。Country
針對此報表,我們不會使用顯示 EmployeeID
、 ReportsTo
或 Country
屬性。 若要移除這些 BoundFields,您可以:
- 使用 [欄位] 對話框,按下 GridView 智慧標記中的 [編輯資料行] 連結,以顯示此對話方塊。 接下來,從左下清單選取 BoundFields,然後按兩下紅色 X 按鈕以移除 BoundField。
- 從 [來源] 檢視手動編輯 GridView 的宣告式語法,刪除
<asp:BoundField>
您想要移除之 BoundField 的 元素。
移除 EmployeeID
、 ReportsTo
和 Country
BoundFields 之後,GridView 的標記看起來應該像這樣:
<asp:GridView ID="GridView1" runat="server"
AutoGenerateColumns="False" DataKeyNames="EmployeeID"
DataSourceID="ObjectDataSource1">
<Columns>
<asp:BoundField DataField="LastName" HeaderText="LastName"
SortExpression="LastName" />
<asp:BoundField DataField="FirstName" HeaderText="FirstName"
SortExpression="FirstName" />
<asp:BoundField DataField="Title" HeaderText="Title"
SortExpression="Title" />
<asp:BoundField DataField="HireDate" HeaderText="HireDate"
SortExpression="HireDate" />
</Columns>
</asp:GridView>
請花點時間在瀏覽器中檢視我們的進度。 此時,您應該會看到一個數據表,其中包含每位員工的記錄和四個數據行:一個用於員工的姓氏、一個用於名字、一個用於職稱,另一個用於雇用日期。
圖 3:每個 LastName
員工都會顯示 、 FirstName
、 Title
和 HireDate
字段, (按兩下即可檢視全大小影像)
步驟 2:在單一數據行中顯示名字和姓氏
目前,每個員工的名字和姓氏都會顯示在個別的數據行中。 最好改為將它們合併成單一數據行。 若要達成此目的,我們需要使用TemplateField。 我們可以新增TemplateField、將所需的標記和數據系結語法新增至該欄位,然後刪除 FirstName
和 LastName
BoundFields,也可以將 BoundField 轉換成 FirstName
TemplateField、編輯 TemplateField 以包含 LastName
值,然後移除 LastName
BoundField。
這兩種方法都會達到相同的結果,但個人上我喜歡盡可能將 BoundFields 轉換成 TemplateFields,因為轉換會自動新增 ,ItemTemplate
EditItemTemplate
並使用 Web 控件和數據系結語法來模擬 BoundField 的外觀和功能。 優點是,我們必須使用TemplateField執行較少的工作,因為轉換程式會為我們執行一些工作。
若要將現有的 BoundField 轉換成 TemplateField,請按兩下 GridView 智慧標記中的 [編輯數據行] 連結,並顯示 [欄位] 對話框。 從左下角的清單中選取 [BoundField] 進行轉換,然後按下右下角的 [將此字段轉換成 TemplateField] 連結。
圖 4:從 [字段] 對話框將 BoundField 轉換成 TemplateField, (按兩下即可檢視完整大小的影像)
繼續並將 FirstName
BoundField 轉換成 TemplateField。 在此變更之後,Designer 沒有任何感知差異。 這是因為將 BoundField 轉換成 TemplateField 會建立 TemplateField,以維護 BoundField 的外觀和風格。 雖然 Designer 目前沒有任何視覺差異,但此轉換程式已取代 BoundField 的宣告式語法 - <asp:BoundField DataField="FirstName" HeaderText="FirstName" SortExpression="FirstName" />
使用下列 TemplateField 語法:
<asp:TemplateField HeaderText="FirstName" SortExpression="FirstName">
<EditItemTemplate>
<asp:TextBox ID="TextBox1" runat="server"
Text='<%# Bind("FirstName") %>'></asp:TextBox>
</EditItemTemplate>
<ItemTemplate>
<asp:Label ID="Label1" runat="server"
Text='<%# Bind("FirstName") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
如您所見,TemplateField 是由兩個範本ItemTemplate
所組成,其具有 Label,其Text
屬性設定為數據欄位的值,以及EditItemTemplate
具有屬性也設定為數據欄位之 FirstName
TextBox 控制件Text
的 FirstName
。 數據系結語法 - <%# Bind("fieldName") %>
- 表示數據欄位 fieldName
系結至指定的 Web 控制件屬性。
若要將數據 LastName
域值新增至此 TemplateField,我們需要在 中新增另一個標籤 Web 控制件, ItemTemplate
並將其 Text
屬性系結至 LastName
。 這可以手動或透過 Designer 來完成。 若要手動執行,只要將適當的宣告式語法新增至 ItemTemplate
:
<asp:TemplateField HeaderText="FirstName" SortExpression="FirstName">
<EditItemTemplate>
<asp:TextBox ID="TextBox1" runat="server"
Text='<%# Bind("FirstName") %>'></asp:TextBox>
</EditItemTemplate>
<ItemTemplate>
<asp:Label ID="Label1" runat="server"
Text='<%# Bind("FirstName") %>'></asp:Label>
<asp:Label ID="Label2" runat="server"
Text='<%# Bind("LastName") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
若要透過 Designer 新增它,請按下 GridView 智慧標記中的 [編輯範本] 連結。 這會顯示 GridView 的範本編輯介面。 在此介面的智慧標記中,是 GridView 中的範本清單。 因為我們此時只有一個 TemplateField,下拉式清單中所列的唯一範本是 TemplateField 的 FirstName
範本以及 EmptyDataTemplate
和 PagerTemplate
。 EmptyDataTemplate
如果指定範本,則會用來呈現 GridView 的輸出,如果數據未繫結至 GridView,PagerTemplate
則為 ;如果指定,則會使用 轉譯支援分頁之 GridView 的分頁介面。
圖 5:GridView 的範本可以透過 Designer (按兩下即可檢視全大小的影像)
若要在 TemplateField 中顯示 ,LastName
請將 [捲標] 控件從 [工具箱] 拖曳到 FirstName
GridView 範本編輯介面中的 TemplateFieldItemTemplate
。FirstName
圖 6:將標籤 Web 控件新增至 FirstName
TemplateField 的 ItemTemplate (按兩下即可檢視完整大小的影像)
此時,新增至 TemplateField 的 Label Web 控件已將其 Text
屬性設定為 「Label」。 我們需要變更這個屬性,以便改為系結至數據欄位的值 LastName
。 若要完成此動作,請按兩下標籤的智慧標記,然後選擇 [編輯 DataBindings] 選項。
圖 7:從標籤的智慧標記中選擇 [編輯 DataBindings] 選項 (按兩下即可檢視大小完整的影像)
這會顯示 [DataBindings] 對話框。 您可以從這裡選取屬性,從左側清單參與數據系結,然後選擇欄位,將數據系結至右邊的下拉式清單中。 Text
從左側選擇 屬性,然後從右側選擇 LastName
字段,然後按兩下 [確定]。
圖 8:將 Text
屬性系結至 LastName
數據欄位, (按兩下即可檢視大小完整的影像)
注意
[DataBindings] 對話框可讓您指出是否要執行雙向數據系結。 如果您未核取此內容,則會使用資料系結語法 <%# Eval("LastName")%>
,而不是 <%# Bind("LastName")%>
。 這兩種方法都適用於本教學課程。 插入和編輯數據時,雙向數據系結會變得很重要。 不過,為了只顯示數據,任一種方法都同樣正常運作。 我們將在未來的教學課程中詳細討論雙向數據系結。
請花點時間透過瀏覽器檢視此頁面。 如您所見,GridView 仍然包含四個數據行;不過,數據FirstName
行現在會FirstName
同時列出 和數據LastName
域值。
圖 9: FirstName
和 LastName
值都會顯示在單一數據行中 (按鍵即可檢視完整大小的影像)
若要完成此第一個步驟,請移除 LastName
BoundField,並將 TemplateField 的 HeaderText
屬性重新命名FirstName
為 “Name”。 這些變更之後,GridView 的宣告式標記看起來應該如下所示:
<asp:GridView ID="GridView1" runat="server"
AutoGenerateColumns="False" DataKeyNames="EmployeeID"
DataSourceID="ObjectDataSource1">
<Columns>
<asp:TemplateField HeaderText="Name" SortExpression="FirstName">
<EditItemTemplate>
<asp:TextBox ID="TextBox1" runat="server"
Text='<%# Bind("FirstName") %>'></asp:TextBox>
</EditItemTemplate>
<ItemTemplate>
<asp:Label ID="Label1" runat="server"
Text='<%# Bind("FirstName") %>'></asp:Label>
<asp:Label ID="Label2" runat="server"
Text='<%# Eval("LastName") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField DataField="Title" HeaderText="Title"
SortExpression="" Title" />
<asp:BoundField DataField="HireDate" HeaderText="
HireDate" SortExpression="" HireDate" />
</Columns>
</asp:GridView>
圖 10:每位員工的名字和姓氏都會顯示在一個數據行中, (按兩下即可檢視大小完整的影像)
步驟 3:使用行事曆控件顯示HiredDate
欄位
在 GridView 中以文字顯示數據域值,就像使用 BoundField 一樣簡單。 不過,在某些案例中,數據最好是使用特定的 Web 控件來表示,而不只是文字。 使用 TemplateFields 可以進行這類數據的顯示自定義。 例如,我們可以使用 ([行事曆] 控件來顯示行事曆) ,而不是將員工的僱用日期顯示為文字,而是使用 行事歷控件 來顯示行事曆) 。
若要達成此目的,請先將 HiredDate
BoundField 轉換成 TemplateField。 只要移至 GridView 的智慧標記,然後按兩下 [編輯資料行] 連結,就會顯示 [字段] 對話方塊。 HiredDate
選取 BoundField,然後按兩下 [將此字位轉換成 TemplateField]。
圖 11:將 HiredDate
BoundField 轉換成 TemplateField (按兩下即可檢視大小完整的影像)
如我們在步驟 2 中所見,這會使用包含 的 TemplateField 取代 BoundField,ItemTemplate
EditItemTemplate
其Text
屬性會使用數據系結語法<%# Bind("HiredDate")%>
系結至HiredDate
值的 Label 和 TextBox。
若要以行事曆控件取代文字,請移除標籤並新增行事歷控件來編輯範本。 從 Designer,從 GridView 的智慧標記中選取 [編輯範本],然後從下拉式清單中選擇 HireDate
TemplateField ItemTemplate
的 。 接下來,刪除標籤控件,並將 [行事曆] 控件從 [工具箱] 拖曳至範本編輯介面。
圖 12:將行事歷控件新增至 HireDate
TemplateField 的 ItemTemplate
(按兩下即可檢視完整大小的影像)
此時 GridView 中的每個數據列都會在其 TemplateField 中包含 HiredDate
行事曆控件。 不過,員工的實際 HiredDate
值不會在 [行事曆] 控件中的任何位置設定,因此每個行事歷控件默認都會顯示目前的月份和日期。 若要解決此問題,我們需要將每位員工 HiredDate
指派給行事歷控件的 SelectedDate 和 VisibleDate 屬性。
從 [行事歷] 控件的智能標記中,選擇 [編輯 DataBindings]。 接下來,將 SelectedDate
和 VisibleDate
屬性系結至 HiredDate
數據欄位。
圖 13:將 和 VisibleDate
屬性系結SelectedDate
至HiredDate
數據欄位 (按鍵即可檢視大小完整的影像)
注意
行事歷控件的選取日期不一定可見。 例如,行事曆可能會有 1999 年 8 月 1 日作為選取的日期,但會顯示目前月份和年份。 選取的日期和可見日期是由行事曆控件的 SelectedDate
和 VisibleDate
屬性所指定。 由於我們想要同時選取員工的 HiredDate
,並確定其顯示,我們必須將這兩個屬性系結至 HireDate
數據欄位。
在瀏覽器中檢視頁面時,行事歷現在會顯示員工的僱用日期月份,並選取該特定日期。
圖 14:員工 HiredDate
在行事歷控件中顯示 (按兩下即可檢視大小完整的影像)
注意
相對於到目前為止我們所看到的所有範例,在本教學課程中,我們 並未 將此 GridView 的 屬性設定 EnableViewState
為 False
。 此決策的原因是按兩下 [行事曆] 控制的日期會導致回傳,將 [行事曆] 選取的日期設定為剛按下的日期。 不過,如果 GridView 的檢視狀態已停用,則在每個回傳上,GridView 的數據都會重新繫結至其基礎數據源,這會導致行事歷選取的日期 設定回 員工的 HireDate
,並覆寫使用者所選擇的日期。
在本教學課程中,這是一個無問題的討論,因為使用者無法更新員工的 HireDate
。 最好設定行事歷控件,使其日期無法選取。 不論為何,本教學課程都會示範在某些情況下必須啟用檢視狀態,才能提供特定功能。
步驟 4:顯示員工為公司工作天數
到目前為止,我們已看到TemplateFields的兩個應用程式:
- 將兩個或多個數據域值合併成一個數據行,以及
- 使用 Web 控制件來表示資料域值,而不是文字
TemplateFields 的第三個用法是顯示 GridView 基礎數據的元數據。 例如,除了顯示員工的僱用日期之外,我們也可能想要有一個數據行,顯示他們在工作上的總天數。
不過,當基礎數據需要在網頁報表中以不同於儲存在資料庫中的格式顯示時,就會出現使用TemplateFields的另一種用法。 Employees
假設數據表有一個Gender
欄位儲存字元M
,或F
表示員工的性別。 在網頁中顯示這項資訊時,我們可能會想要將性別顯示為「男性」或「女性」,而不是「M」或「F」。
這兩個案例都可以藉由在 ASP.NET 頁面的程式代碼後置類別 (或個別類別庫中建立 格式化方法 ,以實作為 Shared
從範本叫用的方法) 來處理。 使用稍早所見的相同數據系結語法,從範本叫用這類格式方法。 格式化方法可以採用任意數目的參數,但必須傳回字串。 這個傳回的字串是插入範本中的 HTML。
為了說明這個概念,讓我們增強教學課程,以顯示一個數據行,其中列出員工在工作上的總天數。 這個格式化方法會採用物件, Northwind.EmployeesRow
並傳回員工已採用為字串的天數。 這個方法可以新增至 ASP.NET 頁面的程式代碼後置類別,但 必須 標示為 Protected
或 Public
,才能從範本存取。
Protected Function DisplayDaysOnJob(employee As Northwind.EmployeesRow) As String
' Make sure HiredDate is not NULL... if so, return "Unknown"
If employee.IsHireDateNull() Then
Return "Unknown"
Else
' Returns the number of days between the current
' date/time and HireDate
Dim ts As TimeSpan = DateTime.Now.Subtract(employee.HireDate)
Return ts.Days.ToString("#,##0")
End If
End Function
由於欄位可以包含NULL
資料庫值,HiredDate
因此我們必須先確定該值不是NULL
在繼續進行計算之前。 HiredDate
如果值為 NULL
,我們只會傳回字串 「Unknown」;如果不是 NULL
,我們會計算目前時間與HiredDate
值之間的差異,並傳回天數。
若要利用此方法,我們需要使用數據系結語法,從 GridView 中的 TemplateField 叫用它。 首先,按兩下 GridView 智慧標記中的 [編輯資料行] 連結,然後新增TemplateField,將新的TemplateField新增至 GridView。
圖 15:將新的 TemplateField 新增至 GridView (按兩下即可檢視完整大小的影像)
將這個新的 TemplateField HeaderText
屬性設定為 「Days on the Job」,並將其 ItemStyle
HorizontalAlign
屬性設定為 Center
。 若要從範本呼叫 DisplayDaysOnJob
方法,請新增 ItemTemplate
,並使用下列數據系結語法:
<%# DisplayDaysOnJob(CType(CType(Container.DataItem, DataRowView).Row,
Northwind.EmployeesRow)) %>
Container.DataItem
DataRowView
會傳回對應至 DataSource
系結至 之記錄的GridViewRow
物件。 屬性 Row
會傳回傳遞至 DisplayDaysOnJob
方法的強型別 Northwind.EmployeesRow
。 此數據系結語法可以直接出現在 ItemTemplate
(中,如下列宣告式語法所示) ,也可以指派給 Text
標籤 Web 控件的屬性。
注意
或者,我們只能使用 <%# DisplayDaysOnJob(Eval("HireDate")) %>
傳入 HireDate
值,而不是傳入 EmployeesRow
實例。 不過,此方法 Eval
會傳 Object
回 ,因此我們必須變更方法 DisplayDaysOnJob
簽章,以接受 類型 Object
為的輸入參數。 我們無法盲目地將呼叫轉換成 Eval("HireDate")
, DateTime
因為 HireDate
數據表中的數據 Employees
行可以包含 NULL
值。 因此,我們需要接受 Object
做為 方法的 DisplayDaysOnJob
輸入參數,檢查它是否有資料庫 NULL
值 (可以使用) 來完成 Convert.IsDBNull(objectToCheck)
,然後據以繼續。
由於這些細微之處,我選擇傳入整個 EmployeesRow
實例。 在下一個教學課程中,我們將會看到更適合的範例, Eval("columnName")
以使用語法將輸入參數傳遞至格式化方法。
下列顯示 GridView 在新增 TemplateField 之後的宣告式語法,以及 DisplayDaysOnJob
從 ItemTemplate
呼叫的方法:
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
DataKeyNames="EmployeeID" DataSourceID="ObjectDataSource1">
<Columns>
<asp:TemplateField HeaderText="Name"
SortExpression="FirstName">
<EditItemTemplate>
<asp:TextBox ID="TextBox1" runat="server"
Text='<%# Bind("FirstName") %>'></asp:TextBox>
</EditItemTemplate>
<ItemTemplate>
<asp:Label ID="Label1" runat="server"
Text='<%# Bind("FirstName") %>'></asp:Label>
<asp:Label ID="Label2" runat="server"
Text='<%# Eval("LastName") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField DataField="Title" HeaderText="" Title"
SortExpression="Title" />
<asp:TemplateField HeaderText="HireDate" SortExpression="
HireDate">
<EditItemTemplate>
<asp:TextBox ID="TextBox2" runat="server"
Text='<%# Bind("HireDate") %>'></asp:TextBox>
</EditItemTemplate>
<ItemTemplate>
<asp:Calendar ID="Calendar1" runat="server"
SelectedDate='<%# Bind("HireDate") %>'
VisibleDate='<%# Eval("HireDate") %>'>
</asp:Calendar>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Days On The Job">
<ItemTemplate>
<%# DisplayDaysOnJob(CType(CType(Container.DataItem, DataRowView).Row,
Northwind.EmployeesRow)) %>
</ItemTemplate>
<ItemStyle HorizontalAlign="Center" />
</asp:TemplateField>
</Columns>
</asp:GridView>
圖 16 顯示透過瀏覽器檢視時已完成的教學課程。
圖 16:[員工已在作業上] 的天數顯示 (按兩下即可檢視大小完整的影像)
摘要
GridView 控件中的 TemplateField 可讓顯示數據的彈性高於其他欄位控制件所提供的彈性。 TemplateFields 適用於下列情況:
- 多個數據欄位必須顯示在一個 GridView 資料行中
- 數據最適合使用 Web 控制件來表示,而不是純文字
- 輸出取決於基礎數據,例如顯示元數據或重新格式化數據
除了自定義數據的顯示之外,TemplateFields 也可用來自定義用於編輯和插入數據的使用者介面,如未來教學課程所示。
接下來的兩個教學課程會繼續探索範本,從在DetailsView中使用TemplateFields開始。 接下來,我們將移至 FormView,其會使用範本取代欄位,以在數據的版面配置和結構中提供更大的彈性。
快樂的程序設計!
關於作者
Scott Mitchell 是七份 ASP/ASP.NET 書籍的作者,以及 自 1998 年以來與 Microsoft Web 技術合作的 4GuysFromRolla.com 作者。 Scott 是獨立顧問、訓練員和作者。 他的最新書籍是 Sams 在 24 小時內自行 ASP.NET 2.0。 您可以透過mitchell@4GuysFromRolla.com部落格來連線到 ,您可以在 找到http://ScottOnWriting.NET。
特別感謝
本教學課程系列是由許多實用的檢閱者所檢閱。 本教學課程的首席檢閱者是 Dan Jagers。 想要檢閱即將推出的 MSDN 文章嗎? 如果是,請將一行放在 mitchell@4GuysFromRolla.com。