在 DetailsView 控制項中使用 TemplateFields (VB)

作者:Scott Mitchell

下載 PDF

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 會將UnitPrice、UnitsInStock 和 UnitsOnOrder 數據欄位合併成一個 DetailsView 的數據列。 第二個 TemplateField 會顯示 Discontinued 欄位的值,但如果 Discontinued 是 True,則會使用格式化方法來顯示 “YES” ,否則為 “NO”。

兩個 TemplateField 可用來自定義顯示

圖 1:使用兩個 TemplateField 來自訂顯示(點擊以檢視完整大小的影像)

現在就開始吧!

步驟 1:將數據系結至 DetailsView

在進行上一個教程討論的基礎上,使用 TemplateFields 時,通常最簡單的方法是先建立只包含 BoundFields 的 DetailsView 控件,然後根據需要新增 TemplateFields,或將現有的 BoundFields 轉換為 TemplateFields。 因此,透過設計工具將 DetailsView 新增至頁面,並將其系結至會傳回產品清單的 ObjectDataSource,以啟動本教學課程。 這些步驟會針對每個產品的非布爾值欄位建立具有 BoundFields 的 DetailsView,以及一個布爾值字段的 CheckBoxField(已停止)。

開啟 DetailsViewTemplateField.aspx 頁面,並將 DetailsView 從 [工具箱] 拖曳至設計檢視。 從 DetailsView 的智慧標籤,選擇新增一個新的 ObjectDataSource 控制項,該控制項會調用 ProductsBLL 類別的 GetProducts() 方法。

新增叫用 GetProducts 方法的新 ObjectDataSource 控件

圖 2:新增叫用 GetProducts() 方法的 ObjectDataSource 控件 (按兩下以檢視完整大小的影像)

針對此報表,請移除ProductID、SupplierID、CategoryID和ReorderLevel的BoundFields。 接下來,重新排列 BoundFields,使 CategoryName 和 SupplierName BoundFields 立即出現在 ProductName BoundField 之後。 您可以視需要調整 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),其中列顯示產品的名稱、類別、供應商、價格、庫存數量、訂購數量,以及其已停止販售狀態。

產品的詳細資訊會使用一系列 BoundFields 來顯示

圖 3:產品詳細資訊是使用一系列 BoundFields 顯示(點擊以查看完整大小圖像)

步驟 2:將價格、庫存單位和訂單單位合併成一列

DetailsView 有一列用於顯示UnitPrice、UnitsInStock和UnitsOnOrder欄位的詳細資訊。 我們可以透過新增一個 TemplateField,或將現有的 UnitPrice、UnitsInStock 和 UnitsOnOrder 這三個 BoundField 之一轉換為 TemplateField,來將這些資料欄位結合成單一資料列。 雖然我個人偏好轉換現有的 BoundField,但讓我們藉由新增 TemplateField 來練習。

從單擊 DetailsView 智慧標記中的 [編輯欄位] 連結開始,以顯示 [欄位] 對話方塊。 接下來,新增 TemplateField 並將其屬性設定 HeaderText 為 “Price and Inventory”,並移動新的 TemplateField,使其位於 BoundField 上方 UnitPrice 。

將 New TemplateField 新增至 DetailsView 控件

圖 4:將新的 TemplateField 新增至 DetailsView 控件(按兩下以檢視完整大小的影像)

由於這個新的 TemplateField 將包含目前顯示在 UnitPrice、UnitsInStock 和 UnitsOnOrder BoundFields 中的值,因此我們將它們移除。

此步驟的最後一項工作是定義 ItemTemplate Price 和 Inventory TemplateField 的標記,這可以透過 Designer 中的 DetailsView 範本編輯介面或透過控件的宣告式語法來完成。 如同 GridView,您可以按兩下智慧標記中的 [編輯範本] 連結來存取 DetailsView 的範本編輯介面。 您可以從這裡選取要從下拉式清單中編輯的範本,然後從 [工具箱] 新增任何 Web 控制件。

在本教學中,先將標籤控制項新增至 Price 和 Inventory TemplateField 的 ItemTemplate。 接下來,點擊標籤 Web 控制項智慧標籤中的 [編輯 DataBindings] 連結,並將屬性繫結 Text 至 UnitPrice 欄位。

將標籤的 Text 屬性系結至 UnitPrice 數據欄位

圖 5:將標籤的 Text 屬性系結至 UnitPrice 資料欄位 (按兩下以檢視完整大小的影像)

將價格格式化為貨幣

此外,Label Web 控件 Price 和 Inventory TemplateField 現在只會顯示所選產品的價格。 圖 6 顯示到目前為止透過瀏覽器檢視進度的螢幕快照。

價格和庫存模板欄位顯示價格

圖 6:價格和庫存範本欄位顯示價格(單擊以檢視完整大小的影像)

請注意,產品的價格不會格式化為貨幣。 使用 BoundField 時,可以透過將 HtmlEncode 屬性設定為 False,以及將 DataFormatString 屬性設定為 {0:formatSpecifier} 來設定格式。 不過,對於 TemplateField,必須在資料繫結語法中指定任何格式指示,或是使用在應用程式代碼中定義的某個格式化方法(例如,在 ASP.NET 頁面的程式碼後置類別中)。

若要指定標籤 Web 控件中使用的數據系結語法格式,請按下標籤標智慧標記的 [編輯 DataBindings] 連結,返回 [DataBindings] 對話框。 您可以直接在 [格式] 下拉式清單中輸入格式指示,或選取其中一個定義的格式字串。 如同 BoundField 的 DataFormatString 屬性,會使用 {0:formatSpecifier}來指定格式設定。

UnitPrice針對欄位,請使用指定的貨幣格式設定,方法是選取適當的下拉式清單值或手動輸入 {0:C} 。

將價格格式化為貨幣

圖 7:將價格格式化為貨幣(按兩下以檢視完整大小的影像)

以宣告方式,格式規格會作為Bind 或 Eval方法中的第二個參數表示。 剛透過設計工具進行的設定會導致宣告式標記中的下列數據系結表達式:

<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,然後新增一個 BoundField,其 DataField 屬性設定為 Discontinued。 花點時間執行此動作。 在此變更之後,DetailsView 會顯示已停產產品的文字「True」以及仍在銷售中的產品的文字「False」。

字串 True 和 False 用來顯示已停止的狀態

圖 9:字串 True 和 False 用來顯示已停止的狀態(按兩下以檢視完整大小的影像)

假設我們不希望使用字串 「True」 或 「False」,而是使用 「YES」 和 「NO」。 您可以使用 TemplateField 和格式化方法的協助來執行這類自定義。 格式化方法可以接受任意數目的輸入參數,但必須傳回HTML (作為字串),才能插入範本。

將名為DisplayDiscontinuedAsYESorNO的格式化方法新增至DetailsViewTemplateField.aspx頁面的程式代碼後置類別,此方法會接受Northwind.ProductsRow物件作為輸入參數,並傳回字串。 如上一個教學課程所述,此方法 必須 標示為 Protected 或 Public ,才能從範本存取。

Protected Function DisplayDiscontinuedAsYESorNO(discontinued As Boolean) As String
    If discontinued Then
        Return "YES"
    Else
        Return "NO"
    End If
End Function

這個方法會檢查輸入參數 (discontinued),如果為 True,則傳回 「YES」,否則傳回 「NO」。。

注意

在上一個教學課程中所檢查的格式方法中,我們記得我們傳入的數據欄位可能包含 NULL ,因此需要先檢查員工的 HiredDate 屬性值是否具有資料庫 NULL 值,再存取 EmployeesRow的 HiredDate 屬性。 此處不需要這類檢查,因為數據 Discontinued 行永遠無法指派資料庫 NULL 值。 此外,這就是為什麼 方法可以接受布爾值輸入參數,而不需要接受 ProductsRow 類型的 Object實例或參數。

完成這個格式化方法之後,剩下的就是從 TemplateField 的 ItemTemplate呼叫它。 若要建立TemplateField,請移除 Discontinued BoundField 並新增TemplateField,或將 Discontinued BoundField 轉換成 TemplateField。 然後,從宣告式標記檢視中編輯 TemplateField,使其僅包含一個 ItemTemplate,該模板會叫用 DisplayDiscontinuedAsYESorNO 方法,並傳入目前 ProductRow 實例的 Discontinued 屬性值。 這可透過 Eval 方法存取。 具體來說,TemplateField 的標記看起來應該像這樣:

<asp:TemplateField HeaderText="Discontinued" SortExpression="Discontinued">
    <ItemTemplate>
        <%#DisplayDiscontinuedAsYESorNO(Convert.ToBoolean(Eval("Discontinued")))%> 
    </ItemTemplate>
</asp:TemplateField>

這會導致在轉譯 DetailsView 時叫用 DisplayDiscontinuedAsYESorNO 方法,並傳入 ProductRow 實例的 Discontinued 值。 由於 Eval 方法回傳的值是 Object 類型,但 DisplayDiscontinuedAsYESorNO 方法預期輸入參數的類型為 Boolean,因此我們會將 Eval 方法的傳回值轉型為 Boolean。 方法 DisplayDiscontinuedAsYESorNO 接著會根據收到的值傳回 「YES」 或 「NO」。 傳回的值是此 DetailsView 資料列中所顯示的值(請參閱圖 10)。

YES 或 NO 值現在會顯示在已停止的數據列中

圖 10:[停止的行] 中現在顯示 [是] 或 [否] 值(點擊以查看完整大小的圖片)

摘要

DetailsView 控件中的 TemplateField 在顯示數據方面比其他欄位控制項提供更大的彈性,非常適合於以下情況:

  • 多個數據欄位必須顯示在一個 GridView 資料行中
  • 數據最好使用 Web 控制件來表示,而不是純文字
  • 輸出取決於基礎數據,例如顯示元數據或重新格式化數據

雖然 TemplateFields 允許在轉譯 DetailsView 基礎數據時有更大的彈性,但是 DetailsView 輸出仍會感覺有點 Boxy,因為每個字段都會轉譯為 HTML <table>中的數據列。

FormView 控件在設定轉譯的輸出時提供更大的彈性。 FormView 不包含字段,而不只是一系列範本(ItemTemplate、、 EditItemTemplateHeaderTemplate等等)。 我們將在下一個教學課程中,瞭解如何使用 FormView 來更好地控制版面配置的呈現。

祝您程式設計愉快!

關於作者

斯科特·米切爾,七本 ASP/ASP.NET 書籍和 4GuysFromRolla.com 創始人的作者,自1998年以來一直與Microsoft Web 技術合作。 Scott 擔任獨立顧問、講師和作家。 他的新書是 Sams Teach Yourself ASP.NET 2.0 in 24 Hours。 可以透過 mitchell@4GuysFromRolla.com 聯絡他。

特別感謝

本教學課程系列已經過許多熱心的檢閱者檢閱。 本教學課程的主要檢閱者是 Dan Jagers。 有興趣檢閱我即將推出的 MSDN 文章嗎? 如果是,請在 mitchell@4GuysFromRolla.com給我留言。