在 DetailsView 控制項中使用 TemplateFields (C#)

作者 :Scott Mitchell

下載 PDF

GridView 所提供的相同 TemplateFields 功能也適用於 DetailsView 控件。 在本教學課程中,我們將使用包含 TemplateFields 的 DetailsView 一次顯示一個產品。

簡介

TemplateField 提供比 BoundField、CheckBoxField、HyperLinkField 和其他數據字段控制件更高的轉譯數據彈性。 在 上一個教學課程中, 我們探討如何使用 GridView 中的 TemplateField 來:

  • 在一個數據行中顯示多個數據域值。 具體而言, FirstNameLastName 欄位都會合併成一個 GridView 資料行。
  • 使用替代 Web 控制件來表示資料域值。 我們已瞭解如何使用行事歷控件來顯示 HiredDate 值。
  • 根據基礎數據顯示狀態資訊。 Employees雖然數據表不包含傳回員工在作業上的天數的數據行,但我們能夠在上一個教學課程中使用 TemplateField 和 formatting 方法,在 GridView 範例中顯示這類資訊。

GridView 所提供的相同 TemplateFields 功能也適用於 DetailsView 控件。 在本教學課程中,我們將使用包含兩個TemplateFields的DetailsView,一次顯示一個產品。 第一個 TemplateField 會將、 UnitsInStock和數據UnitsOnOrder欄位合併UnitPrice成一個 DetailsView 數據列。 第二個 TemplateField 會顯示欄位的值Discontinued,但如果 是 true,則會使用格式化方法來顯示 “YES”Discontinued,否則為 “NO”。

兩個 TemplateField 可用來自定義顯示

圖 1:兩個 TemplateField 可用來自定義顯示 (按兩下即可檢視完整大小的影像)

現在就開始吧!

步驟 1:將數據系結至 DetailsView

如上一個教學課程所述,使用TemplateFields時,建立只包含BoundFields的DetailsView控件,然後視需要新增TemplateFields或將現有的 BoundFields 轉換為 TemplateFields,通常最容易開始。 因此,請透過 Designer 將 DetailsView 新增至頁面,並將其系結至會傳回產品清單的 ObjectDataSource,以開始本教學課程。 這些步驟會針對每個產品的非布爾值欄位建立具有 BoundFields 的 DetailsView,以及一個布爾值字段的 CheckBoxField, (已停止) 。

開啟頁面,DetailsViewTemplateField.aspx並將DetailsView從 [工具箱] 拖曳到 Designer。 從 DetailsView 的智慧標記選擇新增 ObjectDataSource 控制件,以叫 ProductsBLL 用 類別的 GetProducts() 方法。

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

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

針對此報表,ProductID請移除 、 CategoryIDSupplierIDReorderLevel BoundFields。 接下來,重新排序 BoundFields,讓 CategoryNameSupplierName BoundFields 緊接在 ProductName BoundField 之後出現。 您可以視需要調整 HeaderText BoundFields 的屬性和格式設定屬性。 如同 GridView,這些 BoundField 層級編輯可以透過 [字段] 對話框 (存取,方法是按下 DetailsView 智慧標記) 或透過宣告式語法的 [編輯字段] 連結來存取。 最後,清除 DetailsView 的 HeightWidth 屬性值,以允許 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 具有、 UnitsInStockUnitsOnOrder 欄位的數據UnitPrice列。 我們可以將這些數據欄位結合成單一數據列與 TemplateField,方法是新增 TemplateField,或將其中一個現有的 UnitPriceUnitsInStockUnitsOnOrder BoundFields 轉換成 TemplateField。 雖然我個人偏好轉換現有的 BoundFields,但讓我們藉由新增 TemplateField 來練習。

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

將新的 TemplateField 新增至 DetailsView 控件

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

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

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

在本教學課程中,請先將標籤新增至 Price 和 Inventory TemplateField 的 ItemTemplate。 接下來,按兩下標籤 Web 控件智慧標記中的 [編輯 DataBindings] 連結,並將 Text 屬性系結至 UnitPrice 字段。

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

圖 5:將標籤的屬性 Text 系結至 UnitPrice 數據欄位, (按兩下即可檢視完整大小的影像)

將價格格式化為貨幣

此外,標籤 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表示。 透過 Designer 所做的設定會導致宣告式標記中的下列資料系結表示式:

<asp:Label ID="Label1" runat="server" Text='<%# Eval("UnitPrice", "{0:C}") %>'/>

將其餘數據欄位新增至 TemplateField

此時,我們已在 Price 和 Inventory TemplateField 中顯示並格式化 UnitPrice 數據欄位,但仍需要顯示 UnitsInStockUnitsOnOrder 字段。 讓我們在價格和括弧下方的一行上顯示這些專案。 從 Designer 中的範本編輯介面,您可以將游標放在範本內,並直接輸入要顯示的文字,即可新增這類標記。 或者,此標記可以直接在宣告式語法中輸入。

新增靜態標記、標籤 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,例如 ProductIDProductName等,則會實作為 BoundFields。 CheckBoxField 會轉譯為已停用的複選框,如果數據欄位的值是 True,則為未核取的複選框。

我們不想顯示 CheckBoxField,而是想要顯示文字,指出產品是否已停止。 為了達成此目的,我們可以從 DetailsView 移除 CheckBoxField,然後新增已將 屬性設定為 DiscontinuedDataField BoundField。 請花點時間執行此動作。 在此變更之後,DetailsView 會顯示已停止產品的文字 「True」,而對於仍在使用中的產品則顯示 「False」。

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

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

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

將格式化方法新增至 DetailsViewTemplateField.aspx 頁面的程式代碼後置類別,這個類別 DisplayDiscontinuedAsYESorNO 接受布爾值做為輸入參數,並傳回字串。 如上一個教學課程所述,這個方法 必須 標示為 protectedpublic ,才能從範本存取。

protected string DisplayDiscontinuedAsYESorNO(bool discontinued)
{
    if (discontinued)
        return "YES";
    else
        return "NO";
}

此方法會檢查輸入參數 (discontinued) ,如果為 true,則傳回 “YES”。

注意

在上一個教學課程中檢查的格式方法中,我們回想一下,我們傳入可能包含 NULL 的數據欄位,因此需要檢查員工 HiredDate 屬性值是否具有資料庫 NULL 值,才能存取 EmployeesRow's 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((bool)
          Eval("Discontinued")) %>
    </ItemTemplate>
</asp:TemplateField>

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

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

圖 10:[是] 或 [否] 值現在會顯示在 [已停止的數據列] ([按兩下] 以檢視完整大小的影像)

摘要

DetailsView 控件中的 TemplateField 可讓顯示數據的彈性高於其他欄位控件所提供的彈性,而且適用於下列情況:

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

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

FormView 控件在設定轉譯的輸出時提供更大的彈性。 FormView 不包含字段,而是只包含一系列範本, (ItemTemplateEditItemTemplateHeaderTemplate等等) 。 我們將在下一個教學課程中瞭解如何使用 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放在 。