はじめに
ASP.NETの最大の手落ちは、ネストされたグリッドビューやユーザーコントロールビューの機能を簡単に作成する方法が用意されていないという点です(ここで言う「ネスト」とは、GridViewのセルの中に別のコントロールを配置するという意味です。他のグリッドやユーザーコントロールグリッドを任意のnレベルの深さまでネストする機能のことを指します)。詳細までデータを伝え、完全な編集機能を組み込み、イベント処理を追加するというのは、非常に手間暇のかかる作業です。これは、ASP.NETでWebアプリケーションを開発するときの大きな課題です。
例えば、Northwindデータベースに保存されている、顧客、注文、注文の詳細、製品情報といったデータを、互いに関連付けて表示したいとしましょう。これを実現する方法としては、複数のページをリンクでたどっていく形にして、ページを進むごとに、関連する情報の明細を掘り下げていくという仕組みにするのが簡単です。しかし、こうした形の実装方法では、クリック、ポスト、ページ遷移を延々と続ける形になってしまうので今一つです(Atlasの非同期機能を使用したとしても、膨大な回数のクリックが必要になります)。おまけに、部分的な状態変化やデータベースの変更に伴って、編集が非常に厄介になるおそれがあります。
この記事では、nレベルの深さのASP.NETプレゼンテーションを作成する基本的な方法を紹介します。この方法なら、必要なラウンドトリップの数が大幅に減り、データ管理が大きく改善されて、複雑なビューを簡単に作成できます(ただ、正直なところ、これはMicrosoftが対処すべき問題だと思います。この記事で紹介する実装スタイルを採用してもらえれば、ASP.NETで込み入ったGUIを作成するときの苦労が軽減されるのですが)。
目標はシンプルです。各顧客のすべての注文を単一のページに表示できるようにします(図1を参照)。なお、今回の例では見栄えを考慮しません。スタイルシートを使えば、しゃれた外観を簡単に実現できるはずです。
GridViewを使用したマスター/詳細ビューの作成
この記事では、スペース上の都合から、2レベルのネストのみを取り上げます。しかし、終わりまで読むと分かるように、任意のnレベルのネストにも同じ方法を適用できます。ただし、非常に複雑なプレゼンテーションスタイルの場合は帯域幅が問題になる可能性があるという点に注意してください。
ページの構成要素
ネストの各レベルは、次の基本的な要素で構成されます。
- ページまたはユーザーコントロール(この例ではどちらも基本的には同じ役割を果たす)
- GridView(または同様のコントロール)
- UserControl(ネスト要素はこの中に配置される)
- UserControl内に配置するネストされるコントロール(個々のコントロールまたは別のGridView)
ネストされたビューの最上位レベルは、ASP.NETのWebページです。このページは、プレゼンテーション層のルートになる重要な場所であり、セッション中のユーザーデータを格納し、変更を保持する場所でもあります。
ページレベルのGridViewは、リレーションの最上位レベルのデータを次々と表示するだけです(これは最終的にはHTMLテーブルとして表示されます)。
2番目以降のネストの各レベルでは、UserControlを使用します。これは、プレゼンテーションの各部分を管理しやすい複数のパーツに分割するための重要な要素です。UserControlとは要するに、サブビューをデザインし、サブビューの分離コードを実装するための、空白のキャンバスです。
最後に、ネストされた子コントロールがUserControl上に表示されます。ここでは、仕組みの部分(つまり分離コード)を無視して、ビューの作成に的を絞ることにしましょう。
ビューの各部分の構築
プレゼンテーションの各部分を理解するには、簡単な説明付きで各手順を見ていくのが一番です。GridView、スマートタグ、UserControlになじみがないユーザーでも、細かい手順を見ることで、プロセスを把握できるはずです。
- 新しいWebページを作成します(または手持ちのプロジェクト内の既存のページを使用します)。
- そのページにGridViewを追加します。ページ全体の構成要素として、GridView以外の要素も含まれている場合は、複数のページの外観を統一するための方法として、マスターページを検討してみるとよいでしょう。またここでは、DataListコントロールやRepeaterコントロールも使えます。
- マスターオブジェクトのデータの各要素について、連結列を定義します(私の場合は、カスタムオブジェクトの方をよく使います。カスタムコントロールの方が細かく制御できますし、プレゼンテーション層にADO.NETを持ち込まなくて済むからです)。
- 連結列をテンプレート列に変換します。そのためには、GridViewの右上のスマートタグをクリックし、スマートメニューの[Edit Columns]をクリックします。次に、対象のフィールドを選択して、連結列をテンプレート列に変換するためのリンクをクリックします(図2を参照)。
- [Fields]ダイアログを閉じます。
- プロジェクトにUserControlを追加します。
- GridViewのスマートタグを再度クリックし、[Edit Templates]をクリックします。
- ソリューションエクスプローラからUserControlをItemTemplateにドラッグ&ドロップし、既存のLabelとTextBoxを削除して、スマートタグのメニューの[Edit UserControl]をクリックします(図3を参照)。
- UserControlに別のGridViewを追加すると、基本的なデザインは完了です。
以上の手順を完了した時点では、おおむねリスト1のようなASPコードになります。
<%@ Page Language="VB" AutoEventWireup="false" CodeFile="Default.aspx.vb" Inherits="_Default" %> <%@ Register Src="Orders.ascx" TagName="Orders" TagPrefix="uc2"%> <%@ Register Src="OrdersControl.ascx" TagName="OrdersControl" TagPrefix="uc1" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" > <head runat="server"> <title>Untitled Page</title> </head> <body> <form id="form1" runat="server"> <div> <asp:GridView ID="GridView1" runat="server" Height="191px" Width="325px" AutoGenerateColumns="False"> <Columns> <asp:BoundField DataField="CustomerID" HeaderText="Customer ID"> <ItemStyle VerticalAlign="Top" /> <HeaderStyle Wrap="False" /> </asp:BoundField> <asp:BoundField DataField="CompanyName" HeaderText="Company Name"> <ItemStyle VerticalAlign="Top" /> <HeaderStyle Wrap="False" /> </asp:BoundField> <asp:BoundField DataField="ContactName" HeaderText="Contact Name"> <ItemStyle VerticalAlign="Top" /> <HeaderStyle Wrap="False" /> </asp:BoundField> <asp:TemplateField HeaderText="Order Shipping Details"> <EditItemTemplate> </EditItemTemplate> <ItemTemplate> <uc2:Orders ID="Orders1" runat="server"/> </ItemTemplate> <ItemStyle VerticalAlign="Top" /> <HeaderStyle Wrap="False" /> </asp:TemplateField> </Columns> </asp:GridView> </div> </form> </body> </html>
ここからさらに開発を進めるときには、次のような手順になります。
- UserControlに配置した2番目のGridViewについて、連結列を定義します。
- ネストのレベルをさらに深める場合は、2番目以降のUserControlに対して同じ手順を繰り返します。
ネストされたビューを手軽に実現
ネストされた複雑なビューを作成するのは、場合によっては非常に困難です。私のもとに届くメールの数を見ても、ネストされたビュー(およびキーボードフック)に関する質問が一番多く寄せられています。この記事では、基本的なネストのプレゼンテーションを作成する方法を説明しました。肝心なのは、ネストするコントロールとUserControlを格納するフィールドにはテンプレート列を使用するという点です。各サブビューの分離コードを管理するうえで、これらのUserControlは重要です。