在 DetailsView 控制項中使用 TemplateFields (C#)
由斯科特· 米切爾
GridView 所提供的相同 TemplateFields 功能也可透過 DetailsView 控件取得。 在本教學課程中,我們將使用包含 TemplateFields 的 DetailsView,一次顯示一個產品。
簡介
TemplateField 提供比 BoundField、CheckBoxField、HyperLinkField 和其他數據字段控制件更高的轉譯數據彈性。 在上 一個教學課程中 ,我們探討如何使用 GridView 中的 TemplateField 來:
- 在一個數據行中顯示多個數據域值。 具體而言,
FirstName
和LastName
欄位都會合併成一個 GridView 資料行。 - 使用替代 Web 控制件來表示資料域值。 我們已瞭解如何使用行事歷控件來顯示
HiredDate
值。 - 根據基礎數據顯示狀態資訊。
Employees
雖然數據表未包含傳回員工在職天數的數據行,但我們能夠在上一個教學課程中使用 TemplateField 和格式化方法,在 GridView 範例中顯示這類資訊。
GridView 所提供的相同 TemplateFields 功能也可透過 DetailsView 控件取得。 在本教學課程中,我們將使用包含兩個TemplateFields的DetailsView,一次顯示一個產品。 第一個 TemplateField 會將、 UnitsInStock
和數據UnitsOnOrder
欄位合併UnitPrice
成一個 DetailsView 數據列。 第二個 TemplateField 會顯示欄位的值Discontinued
,但如果 是 true
,則會使用格式化方法來顯示 “YES”Discontinued
,否則為 “NO”。
圖 1:使用兩個 TemplateField 來自定義顯示 (按一下即可檢視完整大小的影像)
現在就開始吧!
步驟 1:將數據系結至 DetailsView
如上一個教學課程所述,使用TemplateFields時,建立只包含BoundFields的DetailsView控件,然後視需要新增TemplateFields或將現有的 BoundFields 轉換為 TemplateFields,通常最簡單的方式。 因此,透過設計工具將 DetailsView 新增至頁面,並將其系結至會傳回產品清單的 ObjectDataSource,以啟動本教學課程。 這些步驟會針對每個產品的非布爾值欄位建立具有 BoundFields 的 DetailsView,以及一個布爾值字段的 CheckBoxField(已停止)。
開啟頁面, DetailsViewTemplateField.aspx
並將DetailsView從 [工具箱] 拖曳至設計工具。 從 DetailsView 的智慧標記選擇新增會叫 ProductsBLL
用類別方法的新 GetProducts()
ObjectDataSource 控制件。
圖 2:新增叫用 GetProducts()
方法的 ObjectDataSource 控件 (按兩下以檢視完整大小的影像)
針對此報表,ProductID
請移除 、 CategoryID
SupplierID
和 ReorderLevel
BoundFields。 接下來,重新排序 BoundFields,讓 CategoryName
和 SupplierName
BoundFields 立即出現在 BoundField 之後 ProductName
。 您可以視需要調整 HeaderText
BoundFields 的屬性和格式設定屬性。 如同 GridView,這些 BoundField 層級的編輯可以透過 [字段] 對話框執行(可透過單擊 DetailsView 智慧標記中的 [編輯欄位] 連結,或透過宣告式語法來存取。 最後,清除 DetailsView 的 Height
和 Width
屬性值,以允許 DetailsView 控件根據顯示的數據展開,並核取智慧標記中的 [啟用分頁] 複選框。
進行這些變更之後,您的 DetailsView 控件宣告式標記看起來應該類似下列內容:
<asp:DetailsView ID="DetailsView1" runat="server" AutoGenerateRows="False"
DataKeyNames="ProductID" DataSourceID="ObjectDataSource1" AllowPaging="True"
EnableViewState="False">
<Fields>
<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="QuantityPerUnit"
HeaderText="Qty/Unit" SortExpression="QuantityPerUnit" />
<asp:BoundField DataField="UnitPrice" HeaderText="Price"
SortExpression="UnitPrice" />
<asp:BoundField DataField="UnitsInStock"
HeaderText="Units In Stock" SortExpression="UnitsInStock" />
<asp:BoundField DataField="UnitsOnOrder"
HeaderText="Units On Order" SortExpression="UnitsOnOrder" />
<asp:CheckBoxField DataField="Discontinued"
HeaderText="Discontinued" SortExpression="Discontinued" />
</Fields>
</asp:DetailsView>
請花點時間透過瀏覽器檢視頁面。 此時,您應該會看到一個列出的單一產品(Chai),其中列顯示產品的名稱、類別、供應商、價格、庫存單位、訂單單位,以及其已停止狀態。
圖 3:產品的詳細數據是使用一系列 BoundFields 顯示(按兩下以檢視完整大小的影像)
步驟 2:將價格、庫存單位和訂單單位合併成一列
DetailsView 具有、 UnitsInStock
和 UnitsOnOrder
欄位的數據UnitPrice
列。 我們可以藉由新增 TemplateField 或將其中一個現有 UnitPrice
、 UnitsInStock
和 BoundField 轉換成 TemplateField,將這些數據欄位結合成單一數據列與 UnitsOnOrder
TemplateField。 雖然我個人偏好轉換現有的 BoundField,但讓我們藉由新增 TemplateField 來練習。
從單擊 DetailsView 智慧標記中的 [編輯欄位] 連結開始,以顯示 [欄位] 對話方塊。 接下來,新增 TemplateField 並將其屬性設定 HeaderText
為 “Price and Inventory”,並移動新的 TemplateField,使其位於 BoundField 上方 UnitPrice
。
圖 4:將新的 TemplateField 新增至 DetailsView 控件(按兩下以檢視完整大小的影像)
由於這個新的 TemplateField 將包含目前顯示在 、 UnitsInStock
和 UnitsOnOrder
BoundFields 中的UnitPrice
值,因此讓我們將其移除。
此步驟的最後一項工作是定義 ItemTemplate
Price 和 Inventory TemplateField 的標記,這可以透過 Designer 中的 DetailsView 範本編輯介面或透過控件的宣告式語法來完成。 如同 GridView,您可以按兩下智慧標記中的 [編輯範本] 連結來存取 DetailsView 的範本編輯介面。 您可以從這裡選取要從下拉式清單中編輯的範本,然後從 [工具箱] 新增任何 Web 控制件。
在本教學課程中,請先將標籤新增至 Price 和 Inventory TemplateField 的 ItemTemplate
。 接下來,按兩下標籤 Web 控件智慧標記中的 [編輯 DataBindings] 連結,並將屬性系結 Text
至 UnitPrice
字段。
圖 5:將標籤的 Text
屬性系結至 UnitPrice
資料欄位 (按兩下以檢視完整大小的影像)
將價格格式化為貨幣
此外,Label Web 控件 Price 和 Inventory TemplateField 現在只會顯示所選產品的價格。 圖 6 顯示到目前為止透過瀏覽器檢視進度的螢幕快照。
圖 6:價格和庫存範本欄位顯示價格(單擊以檢視完整大小的影像)
請注意,產品的價格不會格式化為貨幣。 使用 BoundField 時,可以將 屬性設定為 false
,並將 DataFormatString
屬性設定HtmlEncode
為 ,來設定格式設定。{0:formatSpecifier}
不過,對於 TemplateField,必須在數據系結語法中指定任何格式指示,或是透過使用在應用程式程式代碼內某處定義的格式化方法(例如,在 ASP.NET 頁面的程式代碼後置類別中)。
若要指定標籤 Web 控件中使用的數據系結語法格式,請按下標籤標智慧標記的 [編輯 DataBindings] 連結,返回 [DataBindings] 對話框。 您可以直接在 [格式] 下拉式清單中輸入格式指示,或選取其中一個定義的格式字串。 如同 BoundField 的 DataFormatString
屬性,會使用 {0:formatSpecifier}
來指定格式設定。
UnitPrice
針對欄位,請使用指定的貨幣格式設定,方法是選取適當的下拉式清單值或手動輸入 {0:C}
。
圖 7:將價格格式化為貨幣(按兩下以檢視完整大小的影像)
以宣告方式,格式規格會以 或 Eval
方法中的第二個參數Bind
表示。 剛透過設計工具進行的設定會導致宣告式標記中的下列數據系結表達式:
<asp:Label ID="Label1" runat="server" Text='<%# Eval("UnitPrice", "{0:C}") %>'/>
將其餘數據欄位新增至 TemplateField
此時,我們已在 Price 和 Inventory TemplateField 中顯示和格式化 UnitPrice
數據欄位,但仍需要顯示 UnitsInStock
和 UnitsOnOrder
字段。 讓我們在價格和括弧下方的一行上顯示這些專案。 從設計工具中的範本編輯介面,您可以將游標放在範本內,並直接輸入要顯示的文字,來新增這類標記。 或者,此標記可以直接在宣告式語法中輸入。
新增靜態標記、標籤 Web 控件和數據系結語法,讓 Price 和 Inventory TemplateField 顯示價格和清查資訊,如下所示:
UnitPrice
(庫存/訂單:UnitsInStock / UnitsOnOrder)
執行這項工作之後,DetailsView 的宣告式標記看起來應該如下所示:
<asp:DetailsView ID="DetailsView1" runat="server" AutoGenerateRows="False"
DataKeyNames="ProductID" DataSourceID="ObjectDataSource1" AllowPaging="True"
EnableViewState="False">
<Fields>
<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="QuantityPerUnit"
HeaderText="Qty/Unit" SortExpression="QuantityPerUnit" />
<asp:TemplateField HeaderText="Price and Inventory">
<ItemTemplate>
<asp:Label ID="Label1" runat="server"
Text='<%# Eval("UnitPrice", "{0:C}") %>'></asp:Label>
<br />
<strong>
(In Stock / On Order: </strong>
<asp:Label ID="Label2" runat="server"
Text='<%# Eval("UnitsInStock") %>'></asp:Label>
<strong>/</strong>
<asp:Label ID="Label3" runat="server"
Text='<%# Eval("UnitsOnOrder") %>'>
</asp:Label><strong>)</strong>
</ItemTemplate>
</asp:TemplateField>
<asp:CheckBoxField DataField="Discontinued"
HeaderText="Discontinued" SortExpression="Discontinued" />
</Fields>
</asp:DetailsView>
透過這些變更,我們已將價格和庫存資訊合併成單一 DetailsView 數據列。
圖 8:價格和庫存資訊會顯示在單一數據列中(按兩下以檢視完整大小的影像)
步驟 3:自定義已停止的欄位資訊
數據表 Products
的數據 Discontinued
行是一個位值,指出產品是否已中止。 將 DetailsView (或 GridView) 系結至數據源控件時,布爾值字段會實作為 CheckBoxFields,而非布爾值欄位 Discontinued
,例如 ProductID
、 ProductName
等,則會實作為 BoundFields。 CheckBoxField 會轉譯為已停用的複選框,如果數據欄位的值為 True 且未核取,則會加以檢查。
我們可能不會顯示 CheckBoxField,而是想要顯示指出產品是否停止的文字。 若要達成此目的,我們可以從 DetailsView 移除 CheckBoxField,然後新增已 DataField
將 屬性設定為 Discontinued
的 BoundField。 花點時間執行此動作。 在此變更之後,DetailsView 會顯示已中止產品的文字 「True」,以及仍在使用中之產品的 「False」。
圖 9:字串 True 和 False 用來顯示已停止的狀態(按兩下以檢視完整大小的影像)
假設我們不希望使用字串 「True」 或 「False」,而是使用 「YES」 和 「NO」。 您可以使用 TemplateField 和格式化方法的協助來執行這類自定義。 格式化方法可以接受任意數目的輸入參數,但必須傳回HTML (作為字串),才能插入範本。
將格式化方法新增至 DetailsViewTemplateField.aspx
頁面的程式代碼後置類別,該 DisplayDiscontinuedAsYESorNO
類別接受布爾值做為輸入參數,並傳回字串。 如上一個教學課程所述,此方法 必須 標示為 protected
或 public
,才能從範本存取。
protected string DisplayDiscontinuedAsYESorNO(bool discontinued)
{
if (discontinued)
return "YES";
else
return "NO";
}
這個方法會檢查輸入參數 (discontinued
),如果為 true
,則傳回 「YES」,否則傳回 「NO」。。
注意
在上一個教學課程中所檢查的格式方法中,我們記得我們傳入的數據欄位可能包含 NULL
,因此需要先檢查員工的 HiredDate
屬性值是否具有資料庫 NULL
值,再存取 EmployeesRow
的 HiredDate
屬性。 此處不需要這類檢查,因為數據 Discontinued
行永遠無法指派資料庫 NULL
值。 此外,這就是為什麼 方法可以接受布爾值輸入參數,而不需要接受 ProductsRow
類型的 object
實例或參數。
完成這個格式化方法之後,剩下的就是從 TemplateField 的 ItemTemplate
呼叫它。 若要建立TemplateField,請移除 Discontinued
BoundField 並新增TemplateField,或將 Discontinued
BoundField 轉換成 TemplateField。 然後,從宣告式標記檢視編輯 TemplateField,使其只包含叫用 方法的 Discontinued
ItemTemplateDisplayDiscontinuedAsYESorNO
,並傳入目前ProductRow
實例的 屬性值。 這可透過 Eval
方法存取。 具體來說,TemplateField 的標記看起來應該像這樣:
<asp:TemplateField HeaderText="Discontinued" SortExpression="Discontinued">
<ItemTemplate>
<%# DisplayDiscontinuedAsYESorNO((bool)
Eval("Discontinued")) %>
</ItemTemplate>
</asp:TemplateField>
這會導致 DisplayDiscontinuedAsYESorNO
在轉譯 DetailsView 時叫用 方法,並 ProductRow
傳入實例 Discontinued
的值。 由於方法會 Eval
傳回 類型的 object
值,但 DisplayDiscontinuedAsYESorNO
方法預期類型 bool
為 的輸入參數,因此我們會將 Eval
方法傳回值轉換成 bool
。 方法 DisplayDiscontinuedAsYESorNO
接著會根據收到的值傳回 「YES」 或 「NO」。 傳回的值是此 DetailsView 資料列中所顯示的值(請參閱圖 10)。
圖 10:[已停止的數據列] 中現在顯示 [是] 或 [否] 值(按兩下以檢視完整大小的影像)
摘要
DetailsView 控件中的 TemplateField 允許比其他欄位控制項提供的數據更彈性,而且適用於下列情況:
- 多個數據欄位必須顯示在一個 GridView 資料行中
- 數據最好使用 Web 控制件來表示,而不是純文字
- 輸出取決於基礎數據,例如顯示元數據或重新格式化數據
雖然 TemplateFields 允許在轉譯 DetailsView 基礎數據時有更大的彈性,但是 DetailsView 輸出仍會感覺有點 Boxy,因為每個字段都會轉譯為 HTML <table>
中的數據列。
FormView 控件在設定轉譯的輸出時提供更大的彈性。 FormView 不包含字段,而不只是一系列範本(ItemTemplate
、、 EditItemTemplate
HeaderTemplate
等等)。 我們將在下一個教學課程中,瞭解如何使用 FormView 來達成轉譯版面配置更多的控制權。
快樂的程序設計!
關於作者
斯科特·米切爾,七本 ASP/ASP.NET 書籍和 4GuysFromRolla.com 創始人的作者,自1998年以來一直與Microsoft Web 技術合作。 斯科特擔任獨立顧問、教練和作家。 他的最新書是 山姆斯在24小時內 ASP.NET 2.0。 他可以到達 mitchell@4GuysFromRolla.com, 或通過他的博客,可以在 找到 http://ScottOnWriting.NET。
特別感謝
本教學課程系列已由許多實用的檢閱者檢閱。 本教學課程的主要檢閱者是 Dan Jagers。 有興趣檢閱我即將推出的 MSDN 文章嗎? 如果是,請將一行 mitchell@4GuysFromRolla.com放在 。