|   | 
          
 
            
|  
              
 .NET TIPS 
[ASP.NET]1つのWebフォーム内で一覧/詳細画面を切り替えるには?
山田 祥寛 
2005/09/23 | 
  | 
          
 
            
 
              
 
             | 
        
   Webアプリケーションを構築していると、検索結果などをサマライズする一覧画面と、より詳細なデータを表示する詳細画面が必要となる局面が多い。このような場合に、従来、どのように対処していただろうか。
 DataGridコントロールのSelectedIndexChangedイベントを利用して選択行のキー情報を取得し、これをクエリ情報として付加したうえで、Server.Transferメソッドで詳細画面にリダイレクトするという方法を採っていた方も多いかもしれない(SelectedIndexChangedイベントの詳細については、「TIPS:[ASP.NET]DataGridコントロールに選択ボタンを追加するには?」を参照)。例えば、以下のようにだ。
 
Sub grid_Changed(sender As Object, e As EventArgs) 
  Server.Transfer("description.aspx?id=" & grid.SelectedItem.Cells(0).Text) 
End Sub
 | 
 しかし、このようなコードはいったん自分自身にポストバックしなければならないという意味で直截(ちょくさい)的でないし、ソートやページング機能を伴うグリッドでは、ページを切り替えることで、ページの状態が初期に戻ってしまうのもうれしくない。
PlaceHolderコントロールを用いた一覧/詳細画面の切り替え
 そこで本稿では、ASP.NETのPlaceHolderコントロールを利用して、一覧画面と詳細画面を1つのWebフォーム内で管理する方法を紹介する。PlaceHolderコントロールを利用することで、一覧/詳細画面の切り替えをより直感的なコードで記述できるようになり、グリッドの状態保持を開発者が意識する必要もなくなる。
 なお、本稿のサンプルを実行するに当たっては、あらかじめデータベース上に以下のようなレイアウトを持つbooksテーブルを作成しておく必要がある。
| フィールド名 | 
データ型 | 
概要 | 
| isbn | 
VARCHAR(255) | 
ISBNコード(主キー) | 
| title | 
VARCHAR(255) | 
書名 | 
| price | 
INT | 
価格 | 
| publish | 
VARCHAR(255) | 
出版社 | 
| puslished | 
DATETIME | 
出版日 | 
  | 
| booksテーブルのフィールド・レイアウト | 
 それではさっそく、具体的なコードを見てみることにしよう。
 
<%@ Page ContentType="text/html" Language="C#" %> 
<%@ Import Namespace="System.IO" %> 
<%@ Import Namespace="System.Data" %> 
<%@ Import Namespace="System.Data.SqlClient" %> 
<script runat="Server"> 
 
Hashtable table = null; 
SqlDataReader reader = null; 
 
void Page_Load(Object sender, EventArgs e) { 
  if (!Page.IsPostBack) { 
 
    // booksテーブルからpublishedフィールド昇順にデータを取得 
    SqlConnection db = new SqlConnection("Data Source=(local);User ID=sa;Password=sa;Persist Security Info=True;Initial Catalog=dotnet"); 
    SqlCommand comm = new SqlCommand("SELECT isbn,title,publish FROM books ORDER BY published DESC", db); 
    db.Open(); 
 
    // 取得したDataReaderオブジェクトを 
    // DataGridコントロールにバインド 
    reader = comm.ExecuteReader(); 
    grid.DataBind(); 
    db.Close(); 
  } 
} 
 
// グリッドの選択行が変更されたタイミングで実行 
void grid_Changed(Object sender, EventArgs e) { 
  SqlConnection db = new SqlConnection("Data Source=(local);User ID=sa;Password=sa;Persist Security Info=True;Initial Catalog=dotnet"); 
 
  // 選択された行のISBNコードをキーにbooksテーブルを検索 
  SqlCommand comm = new SqlCommand("SELECT isbn,title,price,publish,published FROM books WHERE isbn=@isbn", db); 
  comm.Parameters.Add("@isbn", grid.SelectedItem.Cells[0].Text); 
  db.Open(); 
  SqlDataReader reader_desc = comm.ExecuteReader(); 
 
  // 取得したDataReaderオブジェクトの内容を 
  // Labelコントロールに反映 
  if (reader_desc.Read()) { 
    isbn.Text = reader_desc.GetString(0); 
    title.Text = reader_desc.GetString(1); 
    price.Text = reader_desc.GetInt32(2).ToString("#,#00円"); 
    publish.Text = reader_desc.GetString(3); 
    published.Text = 
      reader_desc.GetDateTime(4).ToString("yyyy年MM月dd日"); 
  } 
  db.Close(); 
 
  // 一覧ビューを不可視、詳細ビューを可視状態に、それぞれ変更 
  listPlace.Visible = false; 
  descPlace.Visible = true; 
} 
void link_Click(Object sender, EventArgs e){ 
  // 一覧ビューを可視、詳細ビューを不可視状態に、それぞれ変更 
  listPlace.Visible = true; 
  descPlace.Visible = false; 
} 
</script> 
<html> 
<head> 
<title>PlaceHolderコントロールによる一覧/詳細画面の切り替え</title> 
</head> 
<body> 
<form runat="Server"> 
 
<asp:PlaceHolder id="listPlace" runat="Server" Visible="True"> 
  <asp:DataGrid id="grid" runat="Server" DataSource="<%# reader %>" 
    DataKeyField="isbn" AutoGenerateColumns="False" 
    OnSelectedIndexChanged="grid_Changed"> 
    <HeaderStyle BackColor="#BB2255" ForeColor="white" /> 
    <ItemStyle BackColor="#FFeeEE" /> 
    <AlternatingItemStyle BackColor="#FFDDDD" /> 
    <Columns> 
      <asp:BoundColumn DataField="isbn" HeaderText="ISBNコード" /> 
      <asp:BoundColumn DataField="title" HeaderText="書名" /> 
      <asp:BoundColumn DataField="publish" HeaderText="出版社" /> 
      <asp:ButtonColumn HeaderText="" ButtonType="PushButton" 
        CommandName="Select" Text="詳細" /> 
    </Columns> 
  </asp:DataGrid> 
</asp:PlaceHolder> 
 
<asp:PlaceHolder id="descPlace" runat="Server" Visible="False"> 
<table cellspacing="0" cellpadding="2" rules="all" border="1" 
  style="border-collapse:collapse;"> 
  <tr> 
    <th align="right" bgcolor="#FFDDDD">ISBNコード</td> 
    <td align="left" bgcolor="#FFEEEE"> 
      <asp:Label id="isbn" runat="Server" /> 
    </td> 
  </tr><tr> 
    <th align="right" bgcolor="#FFDDDD">書名</td> 
    <td align="left" bgcolor="#FFEEEE"> 
      <asp:Label id="title" runat="Server" /></td> 
  </tr><tr> 
    <th align="right" bgcolor="#FFDDDD">価格</td> 
    <td align="left" bgcolor="#FFEEEE"> 
      <asp:Label id="price" runat="Server" /></td> 
  </tr><tr> 
    <th align="right" bgcolor="#FFDDDD">出版社</td> 
    <td align="left" bgcolor="#FFEEEE"> 
      <asp:Label id="publish" runat="Server" /></td> 
  </tr><tr> 
    <th align="right" bgcolor="#FFDDDD">配本日</td> 
    <td align="left" bgcolor="#FFEEEE"> 
      <asp:Label id="published" runat="Server" /></td> 
  </tr> 
</table> 
[<asp:LinkButton id="link" runat="Server" 
  Text="一覧へ" OnClick="link_Click" />] 
</asp:PlaceHolder> 
 
</form> 
</body> 
</html>
 | 
 
 
 | 
 
| 一覧/詳細画面を切り替えるためのWebフォーム(C#版:multi_cs.aspx) | 
 
 
 
<%@ Page ContentType="text/html" Language="VB" %> 
<%@ Import Namespace="System.IO" %> 
<%@ Import Namespace="System.Data" %> 
<%@ Import Namespace="System.Data.SqlClient" %> 
<script runat="Server"> 
 
Dim table As Hashtable 
Dim reader As SqlDataReader 
 
Sub Page_Load(sender As Object, e As EventArgs) 
  If Not Page.IsPostBack Then 
 
    ' booksテーブルからpublishedフィールド昇順にデータを取得 
    Dim db As New SqlConnection("Data Source=(local);User ID=sa;Password=sa;Persist Security Info=True;Initial Catalog=dotnet") 
    Dim comm As New SqlCommand("SELECT isbn,title,publish FROM books ORDER BY published DESC", db) 
    db.Open() 
 
    ' 取得したDataReaderオブジェクトを 
    ' DataGridコントロールにバインド 
    reader = comm.ExecuteReader() 
    grid.DataBind() 
    db.Close() 
  End If 
End Sub 
 
' グリッドの選択行が変更されたタイミングで実行 
Sub grid_Changed(sender As Object, e As EventArgs) 
  Dim db As New SqlConnection("Data Source=(local);User ID=sa;Password=sa;Persist Security Info=True;Initial Catalog=dotnet") 
 
  ' 選択された行のISBNコードをキーにbooksテーブルを検索 
  Dim comm As New SqlCommand("SELECT isbn,title,price,publish,published FROM books WHERE isbn=@isbn", db) 
  comm.Parameters.Add("@isbn", grid.SelectedItem.Cells(0).Text) 
  db.Open() 
  Dim reader_desc As SqlDataReader = comm.ExecuteReader() 
 
  ' 取得したDataReaderオブジェクトの内容を 
  ' Labelコントロールに反映 
  If reader_desc.Read() Then 
    isbn.Text = reader_desc.GetString(0) 
    title.Text = reader_desc.GetString(1) 
    price.Text = reader_desc.GetInt32(2).ToString("#,#00円") 
    publish.Text = reader_desc.GetString(3) 
    published.Text = _ 
      reader_desc.GetDateTime(4).ToString("yyyy年MM月dd日") 
  End If 
  db.Close() 
 
  ' 一覧ビューを不可視、詳細ビューを可視状態に、それぞれ変更 
  listPlace.Visible = False 
  descPlace.Visible = True 
End Sub 
 
Sub link_Click(sender As Object, e As EventArgs) 
  ' 一覧ビューを可視、詳細ビューを不可視状態に、それぞれ変更 
  listPlace.Visible = True 
  descPlace.Visible = False 
End Sub 
</script> 
<html> 
<head> 
<title>PlaceHolderコントロールによる一覧/詳細画面の切り替え</title> 
</head> 
<body> 
<form runat="Server"> 
 
<asp:PlaceHolder id="listPlace" runat="Server" Visible="True"> 
  <asp:DataGrid id="grid" runat="Server" DataSource="<%# reader %>" 
    DataKeyField="isbn" AutoGenerateColumns="False" 
    OnSelectedIndexChanged="grid_Changed"> 
    <HeaderStyle BackColor="#BB2255" ForeColor="white" /> 
    <ItemStyle BackColor="#FFeeEE" /> 
    <AlternatingItemStyle BackColor="#FFDDDD" /> 
    <Columns> 
      <asp:BoundColumn DataField="isbn" HeaderText="ISBNコード" /> 
      <asp:BoundColumn DataField="title" HeaderText="書名" /> 
      <asp:BoundColumn DataField="publish" HeaderText="出版社" /> 
      <asp:ButtonColumn HeaderText="" ButtonType="PushButton" 
        CommandName="Select" Text="詳細" /> 
    </Columns> 
  </asp:DataGrid> 
</asp:PlaceHolder> 
 
<asp:PlaceHolder id="descPlace" runat="Server" Visible="False"> 
<table cellspacing="0" cellpadding="2" rules="all" border="1" 
  style="border-collapse:collapse;"> 
  <tr> 
    <th align="right" bgcolor="#FFDDDD">ISBNコード</td> 
    <td align="left" bgcolor="#FFEEEE"> 
      <asp:Label id="isbn" runat="Server" /> 
    </td> 
  </tr><tr> 
    <th align="right" bgcolor="#FFDDDD">書名</td> 
    <td align="left" bgcolor="#FFEEEE"> 
      <asp:Label id="title" runat="Server" /></td> 
  </tr><tr> 
    <th align="right" bgcolor="#FFDDDD">価格</td> 
    <td align="left" bgcolor="#FFEEEE"> 
      <asp:Label id="price" runat="Server" /></td> 
  </tr><tr> 
    <th align="right" bgcolor="#FFDDDD">出版社</td> 
    <td align="left" bgcolor="#FFEEEE"> 
      <asp:Label id="publish" runat="Server" /></td> 
  </tr><tr> 
    <th align="right" bgcolor="#FFDDDD">配本日</td> 
    <td align="left" bgcolor="#FFEEEE"> 
      <asp:Label id="published" runat="Server" /></td> 
  </tr> 
</table> 
[<asp:LinkButton id="link" runat="Server" 
  Text="一覧へ" OnClick="link_Click" />] 
</asp:PlaceHolder> 
 
</form> 
</body> 
</html>
 | 
 
 
 | 
 
| 一覧/詳細画面を切り替えるためのWebフォーム(VB.NET版:multi_vb.aspx) | 
 PlaceHolderコントロールは、その名のとおり、Webフォーム内のコントロールの置き場所(プレイスホルダ)を確保するためのコントロールだ。アプリケーションから動的にコントロールを追加する場合や、今回のように配下のコンテンツの可視/不可視をまとめて切り替えたい場合などに利用することができる。
 これによく似たサーバ・コントロールとしてPanelコントロールがあるが、こちらがWebControlクラス(System.Web.UI.WebControls名前空間)を継承するのに対して、PlaceHolderコントロールはControlクラス(System.Web.UI名前空間)を継承している。
 つまり、背景色や境界線、フォントなどのスタイル属性そのほか、サーバ・コントロール共通で利用可能な属性を使いたい場合には、Panelコントロールを使用する必要がある。本稿のように、単なるコントロールのプレイスホルダとして利用したい場合には、PlaceHolderコントロールを利用すればよいだろう。
 コード内のコメントを参照していただければ分かるように、PlaceHolderコントロールの可視/不可視はVisibleプロパティを設定するだけで変更できる。このため一覧/詳細画面の切り替えには、DataGridコントロールのSelectedIndexChangedイベント、もしくはHyperLinkコントロールのClickイベントが発生したタイミングで、あらかじめ用意しておいた一覧/詳細のビューのVisibleプロパティを反転させればよい。
 以上を理解できたら、さっそく、サンプル・プログラムを起動してみよう。以下のようにグリッド上の[詳細]ボタン、または詳細画面の[一覧へ]リンクをクリックすることで、一覧/詳細画面が切り替わることが確認できれば成功だ。
  | 
  
  | 
 
  | 
 
| サンプル・アプリケーションの実行結果 | 
 
| 
グリッド上の[詳細]ボタン、または詳細画面の[一覧へ]リンクをクリックすることで、一覧画面(上)と詳細画面(下)が切り替わる。 | 
 なお、ASP.NET 2.0ではMultiViewコントロールを利用することで、同等の処理がよりスマートに実現できるようになる。MultiViewコントロールについては、「ASP.NET 2.0のログイン管理とウィザード・ページ」を参照していただきたい。
 
        
 
|  
 | 
 
generated by  
 | 
 
 
 | 
 
 
	
		Insider.NET 記事ランキング
		
		
			本日
			月間