DetailsView コントロールで TemplateFields を使用する (C#)
GridView で使用できる TemplateFields 機能は、DetailsView コントロールでも使用できます。 このチュートリアルでは、TemplateFields を含む DetailsView を使用して、一度に 1 つの製品を表示します。
はじめに
TemplateField は、BoundField、CheckBoxField、HyperLinkField といったデータ フィールド コントロールよりも高い柔軟性でデータをレンダリングできます。 前のチュートリアルでは、GridView で TemplateField を使用して次のことを行いました。
- 1 つの列に複数のデータ フィールド値を表示する。 具体的には、
FirstName
フィールドとLastName
フィールドの両方を 1 つの GridView 列に結合しました。 - 代替 Web コントロールを使用してデータ フィールド値を表示する。 Calendar コントロールを使用して
HiredDate
値を表示する方法について説明しました。 - 基になるデータに基づいてステータス情報を表示する。
Employees
テーブルには従業員が勤務した日数を返す列は含まれていませんが、前のチュートリアルの GridView の例では、TemplateField と書式設定方法を使用してこのような情報を表示できました。
GridView で使用できる TemplateFields 機能は、DetailsView コントロールでも使用できます。 このチュートリアルでは、2 つの TemplateFields を含む DetailsView を使用して、一度に 1 つの製品を表示します。 最初の TemplateField では、UnitPrice
データ フィールド、UnitsInStock
データ フィールド、UnitsOnOrder
データフィールドが 1 つの DetailsView 行に結合されます。 2 番目の TemplateField には Discontinued
フィールドの値が表示されますが、Discontinued
が true
の場合は書式設定方法を使用して "YES" と表示され、それ以外の場合は "NO" と表示されます。
図 1: TemplateField を 2 つ使用したディスプレイのカスタマイズ (クリックすると全画面表示されます)
それでは始めましょう。
手順 1: データを DetailsView にバインドする
前のチュートリアルで説明したように、TemplateField を使用する場合は、最初に BoundField のみを含む DetailsView コントロールを作成してから新しい TemplateField を追加するか、必要に応じて既存の BoundField を TemplateField に変換する方法が最も簡単なことが多いです。 そのため、このチュートリアルでも、最初にデザイナーを使用して DetailsView をページに追加し、製品の一覧を返す ObjectDataSource にバインドします。 これらの手順では、製品のブール値以外の各フィールドには BoundField を使用し、ブール値フィールドには CheckBoxField を使用 (廃止) して DetailsView を作成します。
DetailsViewTemplateField.aspx
ページを開き、DetailsView をツールボックスからデザイナーにドラッグします。 DetailsView のスマート タグから、ProductsBLL
クラスの GetProducts()
メソッドを呼び出す新しい ObjectDataSource コントロールを選択して追加します。
図 2: GetProducts()
メソッドを呼び出す新しい ObjectDataSource コントロールの追加 (クリックすると全画面表示されます)
このレポートでは、ProductID
、SupplierID
、CategoryID
、ReorderLevel
の各 BoundField を削除します。 次に、BoundField を並べ替えて、CategoryName
BoundField と SupplierName
BoundField が ProductName
BoundField の直後に表示されるようにします。 BoundFields の HeaderText
プロパティや書式設定プロパティは、必要に応じて自由に調整できます。 GridView と同様に、これらの BoundField レベルの編集は、[フィールド] ダイアログ ボックス (DetailsView のスマート タグの [フィールドの編集] リンクをクリックしてアクセス可能) または宣言構文を使用して実行できます。 最後に、DetailsView コントロールを表示されたデータに基づいて展開できるように、DetailsView の Height
プロパティ値と Width
プロパティ値をクリアして、スマート タグの [ページングを有効にする] チェックボックスをオンにします。
変更後の 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>
少し時間をとり、ブラウザーでページを表示してください。 この時点で、製品の名前、カテゴリ、仕入先、価格、在庫単位、注文単位、および生産中止の状態を示す行が表示された 1 つの製品 (Chai) が表示されます。
図 3: 一連の BoundField を使用して表示された製品の詳細 (クリックすると全画面表示されます)
手順 2: 注文時の価格、在庫単位、注文単位を 1 行に結合する
DetailsView には、UnitPrice
、UnitsInStock
、UnitsOnOrder
の各フィールドに対応する行があります。 これらのデータ フィールドは、TemplateField を使用して 1 つの行に結合できます。結合するには、新しい TemplateField を追加するか、既存の UnitPrice
、UnitsInStock
、UnitsOnOrder
の各 BoundField のいずれかを TemplateField に変換します。 個人的には既存の BoundFields を変換する方法が好きなのですが、ここでは新しい TemplateField を追加して結合する練習を行いましょう。
まず、DetailsView のスマート タグに含まれる [フィールドの編集] リンクをクリックして、[フィールド] ダイアログ ボックスを表示します。 次に、新しい TemplateField を追加し、その HeaderText
プロパティを [Price and Inventory]\(価格と在庫\) に設定して、UnitPrice
BoundField の上に配置されるように新しい TemplateField を 移動します。
図 4: DetailsView コントロールに新しい TemplateField を追加 (クリックすると全画面表示されます)
この新しい TemplateField には、現在 UnitPrice
、UnitsInStock
、UnitsOnOrder
の各 BoundField に表示されている値が含まれるので、それらの値を削除しましょう。
この手順の最後のタスクでは、[Price and Inventory]\(価格と在庫\) TemplateField の ItemTemplate
マークアップを定義します。これは、デザイナーで DetailsView のテンプレート編集インターフェイスを使用するか、コントロールの宣言構文を使用して手動で行うことができます。 GridView と同様に、DetailsView のテンプレート編集インターフェイスには、スマート タグの [テンプレートの編集] リンクをクリックしてアクセスできます。 ここで、編集するテンプレートをドロップダウン リストから選択し、ツールボックスから任意の Web コントロールを追加できます。
このチュートリアルでは、まず [Price and Inventory]\(価格と在庫\) TemplateField の ItemTemplate
に Label コントロールを追加します。 次に、Label Web コントロールのスマート タグから [DataBindings の編集] リンクをクリックし、Text
プロパティを UnitPrice
フィールドにバインドします。
図 5: Label の Text
プロパティを UnitPrice
データ フィールドにバインド (クリックすると全画面表示されます)
価格を通貨形式に書式設定する
この形式を追加することで、Label Web コントロールの [Price and Inventory]\(価格と在庫\) TemplateField には、選択した製品の価格だけが表示されるようになります。 図 6 は、ブラウザーを使用して表示した場合の、これまでの経過を示すスクリーン ショットです。
図 6: [Price and Inventory]\(価格と在庫\) TemplateField に表示された価格 (クリックすると全画面表示されます)
製品の価格が通貨形式に書式設定されていないことに注意してください。 BoundField を使用すると、HtmlEncode
プロパティを false
に設定し、DataFormatString
プロパティを {0:formatSpecifier}
に設定することで書式設定を行えます。 ただし、TemplateField の場合は、書式設定命令をデータ バインド構文で、またはアプリケーションのコード内のいずれか (ASP.NET ページの分離コード クラスなど) で定義されている書式設定方法を使用して指定する必要があります。
Label Web コントロールで使用されるデータバインド構文の書式を指定するには、Label のスマート タグから [DataBindings の編集] リンクをクリックして [DataBindings] ダイアログ ボックスに戻ります。 書式設定命令は、[書式] ドロップダウン リストに直接入力することも、定義済みの書式指定文字列のいずれかを選択することも可能です。 BoundField の DataFormatString
プロパティと同様に、書式設定は {0:formatSpecifier}
を使用して指定されます。
UnitPrice
フィールドには、適切なドロップダウン リスト値を選択するか、{0:C}
に手動で入力して指定した通貨書式を使用します。
図 7: 価格を通貨形式に設定 (クリックすると全画面表示されます)
宣言によって、書式設定の仕様は、2 番目のパラメーターとして Bind
または Eval
メソッドに示されます。 デザイナーを使用して行われた設定により、宣言型マークアップでは次のデータバインド式が生成されます。
<asp:Label ID="Label1" runat="server" Text='<%# Eval("UnitPrice", "{0:C}") %>'/>
残りのデータ フィールドを TemplateField に追加する
この時点で、[Price and Inventory]\(価格と在庫\) TemplateField に UnitPrice
データ フィールドを表示および書式設定しましたが、さらに UnitsInStock
フィールドと UnitsOnOrder
フィールドも表示する必要があります。 では、これらのフィールドを価格の下の行にかっこ付きで表示していきましょう。 デザイナーのテンプレート編集インターフェイスからこのようなマークアップを追加するには、テンプレート内にカーソルを置き、表示するテキストを入力します。 または、このマークアップを宣言構文に直接入力することもできます。
静的マークアップ、Label Web コントロール、およびデータバインド構文を追加して、次のように [Price and 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>
これらの変更により、価格と在庫の情報が 1 つの DetailsView 行に統合されました。
図 8: 1 行に表示された価格と在庫情報 (クリックすると全画面表示されます)
手順 3: 生産停止されたフィールド情報のカスタマイズ
Products
テーブルの Discontinued
列は、製品が生産停止されたかどうかを示すビット値です。 DetailsView (または GridView) をデータ ソース コントロールにバインドする場合、ブール値フィールド (Discontinued
など) は CheckBoxField として実装されますが、ブール値以外のフィールド (ProductID
や ProductName
など) は BoundField として実装されます。 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" と返します。
Note
前のチュートリアルで調べた書式設定方法では、NULL
を含むデータ フィールドを渡していたため、EmployeesRow
の HiredDate
プロパティにアクセスする前に、従業員の HiredDate
プロパティ値にデータベースの NULL
値が含まれているかを確認する必要がありました。 Discontinued
列にはデータベースの NULL
値を割り当てることができないため、ここではこのようなチェックは必要ありません。 さらに、ProductsRow
インスタンスや object
タイプのパラメーターを受け入れる必要はなく、ブール型の入力パラメーターを 受け入れることができるのもこのためです。
この書式設定方法が完了したら、最後に TemplateField の ItemTemplate
から呼び出す必要があります。 TemplateField を作成するには、Discontinued
BoundField を削除して新しい TemplateField を追加するか、Discontinued
BoundField を TemplateField に変換します。 次に、宣言型マークアップ ビューで TemplateField を編集し、現在の ProductRow
インスタンスの Discontinued
プロパティの値を渡して DisplayDiscontinuedAsYESorNO
メソッドを呼び出す ItemTemplate だけを含めるようにします。 これにより、Eval
メソッドを使用してアクセスできるようになります。 具体的には、TemplateField のマークアップは次のようになります。
<asp:TemplateField HeaderText="Discontinued" SortExpression="Discontinued">
<ItemTemplate>
<%# DisplayDiscontinuedAsYESorNO((bool)
Eval("Discontinued")) %>
</ItemTemplate>
</asp:TemplateField>
これにより、DetailsView をレンダリングすると ProductRow
インスタンスの Discontinued
値を渡して DisplayDiscontinuedAsYESorNO
メソッドが呼び出されます。 Eval
メソッドは object
タイプの値を返しますが、DisplayDiscontinuedAsYESorNO
メソッドでは bool
タイプの入力パラメーターが期待されるため、Eval
メソッドの戻り値を bool
にキャストします。 次に、DisplayDiscontinuedAsYESorNO
メソッドは受け取る値に応じて "YES" または "NO" を返します。 戻り値は、この DetailsView 行に表示される値です (図 10 を参照)。
図 10: [生産中止] 行に表示された YES または NO 値 (クリックすると全画面表示されます)
まとめ
DetailsView コントロールの TemplateField を使用すると、他のフィールド コントロールで使用するよりも高い柔軟性でデータを表示できます。これは、次の状況において最適です。
- 1 つの GridView 列に複数のデータ フィールドを表示する必要がある場合
- プレーン テキストではなく Web コントロールを使用してデータ表示するのが最適な場合
- 出力が基になるデータ (メタデータの表示やデータの再フォーマットなど) に依存している場合
TemplateFields を使用すると、DetailsView の基になるデータのレンダリングをより柔軟に行うことができますが、各フィールドが HTML <table>
の行としてレンダリングされるため、DetailsView の出力がやや小さく見えます。
FormView コントロールでは、レンダリングされた出力をより柔軟に構成することができます。 FormView には、フィールドではなく一連のテンプレート (ItemTemplate
、EditItemTemplate
、HeaderTemplate
など) のみが含まれます。 次のチュートリアルでは、FormView を使用してレンダリングされたレイアウトをさらに制御する方法について説明します。
プログラミングに満足!
著者について
7 冊の ASP/ASP.NET 書籍の著者であり、4GuysFromRolla.com の創設者である Scott Mitchell は、1998 年から Microsoft Web テクノロジに取り組んでいます。 Scott は、独立したコンサルタント、トレーナー、ライターとして働いています。 彼の最新の本は サムズは24時間で2.0 ASP.NET 自分自身を教えています。 にアクセスするか、ブログを使用して にアクセスmitchell@4GuysFromRolla.comできます。これは でhttp://ScottOnWriting.NET見つけることができます。
特別な感謝
このチュートリアル シリーズは、多くの役に立つ校閲者によってレビューされました。 このチュートリアルのリード レビュー担当者は Dan Jagers でした。 今後の MSDN の記事を確認することに関心がありますか? その場合は、 にmitchell@4GuysFromRolla.com行をドロップしてください。