japan.internet.comThe Internet & IT Network
RSS
  • ニュース
  • コラム
  • リサーチ
  • ヘッドライン
  • 特集
  • ブログ
  • プレスリリース
  • 専門チャンネル
  • イベント
  • ランキング
  • ニュースメール
2009年7月4日
文字サイズ文字サイズ小文字サイズ中文字サイズ大
デベロッパー2008年9月16日 10:00

ASP.NET 3.5の新しいListViewコントロールを使用する

海外海外internet.com発の記事
  • このエントリーを含むはてなブックマーク
  • この記事をクリップ!
  • Buzzurlにブックマーク
  • Yahoo!ブックマークに登録
  • newsing it!
  • この記事をokyuuへインポート

はじめに

 ユーザー中心のアプリケーションを作成するためには、ある種のデータ統合が必要です。少なくとも、リレーショナルデータベースやXMLファイルなどのデータソースからデータを取得した場合は、その書式を整えてから、ユーザーインターフェイスに表示する必要があります。

 以前のバージョンのASP.NETにも、GridViewなど、データ中心の表示コントロールは存在していました。しかし、これらのコントロールは、プロのWeb開発者にとって不可欠なカスタマイズと拡張性の機能に欠けていました。

 この欠点を解決するために、ASP.NET 3.5では、カスタマイズと拡張性の機能に優れているListViewという新しいコントロールが導入されました。これらの機能を使用すると、テンプレートとスタイルを利用してどのような形式のデータでも表示でき、最小限のコードでCRUD(作成、読み取り、更新、削除)操作も実行できます。

 この記事では、新しいListViewコントロールを使用する場合のデータアクセスの手順について詳しく説明します。また、データの編集やイベントの処理など、高度な機能についても説明します。

ListViewコントロールの基礎

 ASP.NETで提供されるほとんどのデータバインドコントロールは、表示されるデータを追加のマークアップで自動的に囲みます。たとえば、GridViewコントロールはレンダリングされるデータをHTMLテーブル(<table>)内に表示しますが、このとき、バインドされるデータの各レコードはテーブル行(<tr>)として表示され、各レコードフィールドは行内のセル(<td>)として表示されます。TemplateField要素や他のツールを使用してGridViewの外観をカスタマイズすることはできますが、GridViewの出力は依然としてtable要素内にあります。

 しかし、データバインドコントロールによって生成される外観のHTMLマークアップを、完全に制御したいこともあります。ListViewコントロールは、まさにこのために導入されました。

 ListViewコントロールの場合、レンダリングされる出力が追加のマークアップで自動的に囲まれることはありません。ListViewコントロールでは、レンダリングされる的確なHTMLを指定するのはあくまでもそれを使用する開発者です。

 的確なマークアップを指定するには、ListViewのビルトインテンプレートを使用します。表1に、ListViewコントロールがサポートするテンプレートを示します。

表1 ListViewコントロールがサポートするテンプレート
テンプレート 目的
AlternatingItemTemplate 連続する項目を区別できるように、交互の項目を異なるマークアップで表示します。
EditItemTemplate 項目が編集モードの場合の表示を制御します。
EmptyDataTemplate ListViewのデータソースがデータを返さない場合の表示を制御します。
EmptyItemTemplate 空の項目の表示を制御します。
GroupSeparatorTemplate 項目のグループ間に表示するコンテンツを制御します。
GroupTemplate コンテンツのテーブル行、div、またはspan要素など、コンテナオブジェクトを指定します。
InsertItemTemplate ユーザーが項目を挿入したときにレンダリングするコンテンツを指定します。
ItemSeparatorTemplate 個々の項目間に表示するコンテンツを制御します。
ItemTemplate 個々の項目に対して表示するコンテンツを制御します。
LayoutTemplate ItemTemplateまたはGroupTemplateで定義されるコンテンツを囲む、table、div、またはspan要素などのコンテナオブジェクトを定義するルート要素を指定します。
SelectedItemTemplate 現在選択されている項目に対して表示するコンテンツを指定します。
 ここで重要なのは、LayoutTemplateItemTemplateの2つです。その名前が示すとおり、LayoutTemplateはListViewコントロールの全体のマークアップを指定し、ItemTemplateはバインドされている各レコードの表示に使用するマークアップを指定します。

 たとえば次のコードは、ListView内のHTML tableコントロールに指定されている項目のリストを表示します。

<asp:ListView ID="..." runat="server" DataSourceID="...">
 <LayoutTemplate>
  <table .......>
   <tr runat="server" ID="itemPlaceholder"></tr>
  </table>
 </LayoutTemplate>
 <ItemTemplate>
  <tr>
   <td><%# Eval("Name") %></td>
  </tr>
 </ItemTemplate>
</asp:ListView>
 上のコードで、LayoutTemplateコントロール内の<tr>コントロールのIDは、itemPlaceHolderに設定されています。これにより、ListViewはItemTemplateコントロールを通じて生成されるコンテンツを<table>コントロール内に配置するようになります。LayoutTemplateとItemTemplateを個別に定義するのでこの指示が必要です。

単純なデータバインディングの例

 ListViewコントロールがサポートするさまざまなテンプレートについて理解したところで、次に、新しいサンプルWebサイトを作ってみましょう。

 このサンプルには「ListViewExample」という名前を付けます(ソースコードは本稿冒頭のリンクからダウンロードできます)。Webサイトを作成したら、メニューから[Website]→[Add New Item]を選択し、「SimpleListView.aspx」という名前の新しいASP.NETページを追加します(リスト1を参照)。このページでは、ListViewコントロールを使用して、AdventureWorksサンプルデータベース内のProductテーブルから製品データを表示します。

リスト1 SimpleListViewページ
<%@ Page Language="C#" %>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
 <link rel="Stylesheet" type="text/css" href="StyleSheet.css" />
 <title>Simple Data Binding Example using ListView control</title>
</head>
<body>
 <form id="form1" runat="server">
  <div>
   <asp:ListView runat="server" ID="productsView" 
    DataSourceID="productSource" DataKeyNames="ProductID">
    <LayoutTemplate>
     <table cellpadding="2" runat="server" id="tblProducts" 
      style="width:460px">
      <tr runat="server" id="itemPlaceholder">
      </tr>
     </table>
     <asp:DataPager runat="server" ID="DataPager" PageSize="3">
      <Fields>
       <asp:NumericPagerField ButtonCount="10" 
        PreviousPageText="<--" NextPageText="-->" />
      </Fields>
     </asp:DataPager>
    </LayoutTemplate>
    <ItemTemplate>
     <tr id="row" style="height:72px" runat="server">
      <td valign="top" class="ProductInfo">
       Product ID : <asp:Label ID="lblProductID" runat="server" 
        Text='<%#Eval("ProductID") %>' />
       <br />
       Name : <asp:Label ID="lblName" runat="server" 
        Text='<%#Eval("Name") %>' />
       <br />
      Product Number : <asp:Label ID="lblProductNumber" 
       runat="server" Text='<%#Eval("ProductNumber") %>' />                                               
      </td>      
     </tr>
    </ItemTemplate>
    <ItemSeparatorTemplate>
     <tr id="separator" style="height:10px" runat="server">
      <td>--------------------------------------------------------  
        ------------------</td>
     </tr>
    </ItemSeparatorTemplate>
    <EmptyDataTemplate>
     There are no products!
    </EmptyDataTemplate>
   </asp:ListView>    
   <asp:SqlDataSource id="productSource" runat="server" 
    DataSourceMode="DataSet"
    ConnectionString="<%$ ConnectionStrings:AdventureWorks%>" 
    SelectCommand="SELECT ProductID,Name,ProductNumber,
    Color,ListPrice FROM Production.Product">
   </asp:SqlDataSource>
  </div>
 </form>
</body>
</html>
 リスト1では、SqlDataSourceコントロールが、ConnectionStringプロパティとSelectCommandプロパティを適切な値に設定することにより、AdventureWorksデータベースのProductテーブルからデータを取得します。ConnectionStringプロパティは、ASP.NET式を通じて「web.config」ファイルから接続文字列を取得します。

 筆者のテストマシンでは、接続文字列は「web.config」内で次のように定義されています。

   <connectionStrings>
    <add name="AdventureWorks"  
     connectionString="server=localhost;uid=sa;
     pwd=thiru;database=AdventureWorks;"/>
    </connectionStrings>
 SqlDataSourceのプロパティを設定したら、次は、ListViewコントロールを通じてそのデータを表示します。LayoutTemplateに含まれるマークアップは次のとおりです。

   <LayoutTemplate>
    <table cellpadding="2" runat="server" id="tblProducts" 
     style="width:460px">
     <tr runat="server" id="itemPlaceholder">
     </tr>
    </table>
    <asp:DataPager runat="server" ID="DataPager" PageSize="3">
     <Fields>
      <asp:NumericPagerField ButtonCount="10" 
       PreviousPageText="<--" NextPageText="-->" />
     </Fields>
    </asp:DataPager>
   </LayoutTemplate>
 LayoutTemplateは、ListViewコントロールを通じて生成される出力のコンテナを定義します。LayoutTemplateコントロールは、ListViewコントロールの全体のレイアウトを定義するtableコントロールに加えて、<asp:DataPager>コントロールも定義します。このコントロールは、ListViewコントロールに対してページング機能を実現するものです。DataPagerコントロールを使用すると、データのページングが可能となり、IPageableItemContainerインターフェイスを実装するすべてのデータバインドコントロールに対して、ナビゲーションコントロールを表示できます(この処理はListViewコントロールが行います)。

 DataPagerコントロールとデータバインドコントロールを関連付けるには、次の2つの方法があります。

  1. DataPagerコントロールのPagedControlIDプロパティをデータバインドコントロールの名前に設定する。
  2. DataPagerコントロールをデータバインドコントロール階層内に配置する。ListViewコントロールの場合は、DataPagerコントロールをLayoutTemplate要素内に配置できます。
 DataPagerのPageSizeプロパティを設定することで、各データページに表示される項目数を制御できます。QueryStringFieldプロパティを設定して、ページをサーバーに送信する方法を変更することもできます。

 DataPagerコントロール内でNumericPageFieldテンプレートを指定すると、ユーザーは、ページ番号を選択することによって特定のページに移動できます。

   <asp:NumericPagerField ButtonCount="10" 
      PreviousPageText="<--"
      NextPageText="-->" />
 ItemTemplate要素は、Eval()文を通じてデータソースコントロールからデータを取得することにより、各レコードの詳細にマークアップを適用します。

 図1は、ブラウザ内でページに移動したときに生成される出力を示しています。

図1 単純なListView。Productデータを取得するSqlDataSourceコントロールにListViewコントロールをデータバインドすることによって生成される出力
図1 単純なListView。Productデータを取得するSqlDataSourceコントロールにListViewコントロールをデータバインドすることによって生成される出力

ListViewコントロールでのデータの編集

 これまでの説明でお分かりのように、ListViewコントロールを使用してデータを表示することは比較的簡単です。さらに、ListView内のデータをユーザーに編集させることも可能です。サンプルWebサイトに「ListViewEditExample.aspx」という名前の新しいASP.NETページを追加し、そのコードをリスト2のように変更します。

リスト2 編集可能なListView
<%@ Page Language="C#" %>
<script runat="server">
void deptsView_ItemUpdated(object sender, 
 ListViewUpdatedEventArgs e)
{
 lblResult.Text = e.AffectedRows.ToString() + 
  " row(s) successfully updated";
}

void deptsView_PagePropertiesChanged(object sender, EventArgs e)
{
 //Set the text to empty when navigating to a different page
 lblResult.Text = "";
}    
</script>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
 <link rel="Stylesheet" type="text/css" href="StyleSheet.css" />
 <title>Editing Data using ListView Control</title>
</head>
<body>
 <form id="form1" runat="server">
  <div>
   <asp:ListView ID="ContactsListView" DataSourceID="deptSource" 
    DataKeyNames="DepartmentID" runat="server" 
    OnItemUpdated="deptsView_ItemUpdated"
    OnPagePropertiesChanged="deptsView_PagePropertiesChanged">
    <LayoutTemplate>
     <table cellpadding="2" width="640px" border="1" 
      runat="server" id="tblProducts">
      <tr id="row1" runat="server" class="header">              
       <th id="header2" runat="server">Name</th>
       <th id="header3" runat="server">Group Name</th>
       <th id="header1" runat="server">Action</th>
      </tr>
      <tr runat="server" id="itemPlaceholder" />
     </table>
     <asp:DataPager runat="server" ID="deptsDataPager" 
      PageSize="3">
      <Fields>
       <asp:NextPreviousPagerField ShowFirstPageButton="True" 
        ShowLastPageButton="True" FirstPageText="|<< " 
        LastPageText=" >>|" NextPageText=" > " 
        PreviousPageText=" < " />
      </Fields>
     </asp:DataPager>
    </LayoutTemplate>
    <ItemTemplate>
     <tr id="row2" runat="server">            
      <td>
       <asp:Label ID="lblName" runat="Server" 
        Text='<%#Eval("Name") %>' />
      </td>
      <td valign="top">
       <asp:Label ID="lblGroupName" runat="Server" 
        Text='<%#Eval("GroupName") %>' />
      </td>
      <td>
       <asp:LinkButton ID="btnEdit" runat="Server" Text="Edit" 
        CommandName="Edit" />
      </td>
     </tr>
    </ItemTemplate>
    <EditItemTemplate>
     <tr style="background-color: #ADD8E6">            
      <td>
       <asp:TextBox ID="txtName" runat="server" 
        Text='<%# Bind("Name") %>' 
        MaxLength="50" /><br />
      </td>
      <td>
       <asp:TextBox ID="txtGroupName" runat="server" Text='<%# 
        Bind("GroupName") %>' MaxLength="50" /><br />
      </td>
      <td>
       <asp:LinkButton ID="btnUpdate" runat="server" 
        CommandName="Update" Text="Update" /> 
       <asp:LinkButton ID="btnCancel" runat="server" 
        CommandName="Cancel" Text="Cancel" />
      </td>
     </tr>
    </EditItemTemplate>
   </asp:ListView>
   <asp:SqlDataSource ID="deptSource" runat="server" 
    ConnectionString="<%$ ConnectionStrings:AdventureWorks %>"
    SelectCommand="SELECT [DepartmentID],[Name],[GroupName] FROM 
    HumanResources.Department" UpdateCommand="UPDATE 
    HumanResources.Department SET Name = @Name, 
    GroupName = @GroupName WHERE DepartmentID = @DepartmentID">
   </asp:SqlDataSource>
   <br /><br />
   <asp:Label runat="server" ID="lblResult" Text="" 
    Font-Bold="true" />
  </div>
 </form>
</body>
</html>
 リスト2のコードは、項目が編集モードの場合にEditItemTemplate要素を使用してコンテンツを生成する方法と、SqlDataSourceコントロールを通じてデータベースを更新する方法を示しています。

 最初に、SqlDataSourceコントロールのUpdateCommandプロパティに、実行するSQL文を指定します。このSQL文が実行されると、ユーザー指定の最新の値でデータベースが更新されます。

   <asp:SqlDataSource ID="deptSource" runat="server" 
       ConnectionString="<%$ ConnectionStrings:AdventureWorks %>"
       SelectCommand="SELECT [DepartmentID],[Name],[GroupName] FROM 
       HumanResources.Department" UpdateCommand="UPDATE 
       HumanResources.Department SET Name = @Name,
       GroupName = @GroupName WHERE DepartmentID = @DepartmentID">
      </asp:SqlDataSource>
 次に、ItemTemplate要素に、ユーザーが項目を編集するときにクリックするリンクを指定します。

   <ItemTemplate>
      ----
      ----
      <asp:LinkButton ID="btnEdit" runat="Server" Text="Edit" 
       CommandName="Edit" />
     </td>
    </tr>
   </ItemTemplate>
 続けて、EditItemTemplateを指定します。ここでは、更新後の部門のNameやGroupNameを入力するテキストボックスと、現在の操作をコミット("Update")またはキャンセル("Cancel")するためのリンクを定義します。

   <EditItemTemplate>
    <tr style="background-color: #ADD8E6">            
     <td>
      <asp:TextBox ID="txtName" runat="server" 
       Text='<%# Bind("Name") %>' 
       MaxLength="50" /><br />
     </td>
     <td>
      <asp:TextBox ID="txtGroupName" runat="server" Text='<%# 
       Bind("GroupName") %>' MaxLength="50" /><br />
     </td>
     <td>
      <asp:LinkButton ID="btnUpdate" runat="server" 
       CommandName="Update" Text="Update" />&nbsp;
      <asp:LinkButton ID="btnCancel" runat="server" 
       CommandName="Cancel" Text="Cancel" />
     </td>
    </tr>
   </EditItemTemplate>
 LinkButtonのアクションは、CommandNameプロパティを目的の値(表2を参照)に設定することにより定義します。

表2 LinkButtonのCommandNameプロパティに指定できる値
説明
Cancel 現在の操作をキャンセルします。
Delete 現在選択されている項目をデータソースから削除します。
Edit ListViewを編集モードに切り替え、EditItemTemplate要素で指定されるコンテンツを表示します。
Insert データソースコントロール内の値を新しいレコードとしてデータソースに保存します。
Update データソースコントロール内の値でデータソースを更新します。
 更新の終了時に、ListViewコントロールはOnItemUpdatedイベントを発生します。このイベントを使用して、ユーザーに対して更新の状態を確認することができます。リスト2のコードでは、ListViewコントロールは2つのイベントを処理しています。

  1. OnItemUpdated ― 名前が示すとおり、このイベントでは、更新処理の最後にカスタムルーチンを実行できます。上記のコードでは、このイベントを使用して、影響を受けたレコード数をユーザーに通知しています。
  2. OnPagePropertiesChanged ― ListViewは、ページプロパティが変更されるときにこのイベントを発生します。リスト内のコードでは、このイベントを使用して、Labelコントロールに格納されているテキストを消去しています。
 ListViewが設定された状態で、ブラウザを使ってこのページにアクセスすると、図2のような出力が得られます。

図2 編集可能なListView。編集可能として設定したListViewコントロールでは、各レコードに対してEditリンクが表示される。このリンクをクリックすると、ListViewコントロールのコンテンツが編集モードに切り替わる
図2 編集可能なListView。編集可能として設定したListViewコントロールでは、各レコードに対してEditリンクが表示される。このリンクをクリックすると、ListViewコントロールのコンテンツが編集モードに切り替わる
 「Edit」ハイパーリンクをクリックすると、ListViewはEditItemTemplateを使用して図3のようなテキストボックスを表示します。ユーザーはこのテキストボックスで、選択されている項目を編集できます。

図3 編集モード。編集モードでは、EditItemTemplate要素によってテキストボックスが生成される。ユーザーはこのテキストボックスに、NameフィールドとGroupNameフィールドの更新後の値を入力できる
図3 編集モード。編集モードでは、EditItemTemplate要素によってテキストボックスが生成される。ユーザーはこのテキストボックスに、NameフィールドとGroupNameフィールドの更新後の値を入力できる
 編集モードでは、右側の列に「Update」リンクと「Cancel」リンクが表示されます。「Update」リンクをクリックして変更をデータベースに保存すると、OnItemUpdatedイベントによって影響を受けたレコード数が表示されます(図4を参照)。

図4 影響を受けたレコード。更新プロセスの終了時に、更新操作の影響を受けたレコード数がLabelコントロールに表示される
図4 影響を受けたレコード。更新プロセスの終了時に、更新操作の影響を受けたレコード数がLabelコントロールに表示される
 ListViewコントロールの主要な機能に関する説明はこれで終わりです。

 本稿では、この機能を使用した例を2つ紹介しました。1つ目の例では、単純なデータドリブンのWebページを作成しました。2つ目の例では、適切な編集と確認のマークアップを指定して、コントロールの更新機能を宣言的に利用する複雑なページを作成しました。また、ListViewコントロールが生成するイベントの処理方法についても説明しました。

 おわかりのように、ListViewの拡張的な特性を利用すると、実行時の動作を各自のニーズに合わせて簡単にカスタマイズできます。

著者紹介

Thiru Thangarathinam(Thiru Thangarathinam)
オブジェクト指向アプリケーション開発方法論を用いたアプリケーションのアーキテクチャ設計、設計、開発、および実装に関して約6年の経験を持つ。ソフトウェアライフサイクル(設計、開発およびテスト)にも精通。 ASP.NET、.NET Framework、Visual C#.NET、Visual Basic.NET、ADO.NET、XML Webサービス、および.NET Remotingのエキスパートであり、MCAD(.NETトラック)、MCSD、およびMCP資格を保有。 多くの書籍や記事を執筆。メールの宛先はthiruthangarathinam@yahoo.com。
関連テーマ
このエントリーを含むはてなブックマーク この記事をクリップ!
BuzzurlにブックマークBuzzurlにブックマーク Yahoo!ブックマークに登録
この記事をokyuuへインポート
最新トップニュース
データメーション
【データメーション】
中国が「Green Dam」フィルタ規制を撤回(7月1日)
Graphic Design Forum
【Graphic Design Forum】
Chris Dickman(6月25日)
プライバシー ジャパン・インターネットコム版
【プライバシー ジャパン・インターネットコム版】
グーグル・ストリートビューの問題について総務省の見解(6月23日)
エンジニアの独り言
【エンジニアの独り言】
システムを「使う」時代のエンジニアに求められるもの(6月2日)
最新ハイテク講座
最新ハイテク講座
電気は家庭でつくる時代へ!燃料電池「エネファーム」(7月3日)
アクセス解析で見るWebマーケティング
アクセス解析で見るWebマーケティング
決定力を探るアクセス解析(7月3日)
百式のネットビジネス研究
百式のネットビジネス研究
ファーストフードを高級っぽく盛り付けて紹介している「Fancy Fast Food」(7月3日)
週刊-サイト別アクセス状況データ
週刊-サイト別アクセス状況データ
ビデオリサーチインタラクティブ調査(月間インターネットオーディエンスデータ)(7月2日)
成約率、反応率を上げる Web 文章術
成約率、反応率を上げる Web 文章術
言葉がダイレクトにキャッシュを生む(7月2日)
不況時代の Web ビジネス最適化講座
不況時代の Web ビジネス最適化講座
アクセス解析エキスパートここだけの話、Web コンシェルジュの“勉強法”こっそり教えます(7月2日)
「Webからの脅威」―その傾向と最新対策
「Webからの脅威」―その傾向と最新対策
不正プログラムの分類(7月1日)
DevX
DevX
JavaScriptとDOMによる動的なWebページの作成(6月30日)
エンジニア転職ノウハウ開発室
エンジニア転職ノウハウ開発室
今のままで大丈夫?3匹の子ブタ的キャリア危険度診断(6月30日)
アイレップの SEM フロンティア
アイレップの SEM フロンティア
Web サイトは「無駄な穴のたくさん開いたじょうご」〜サイト成果向上の基本的な考え方(6月30日)
Copyright 2009 Japan Internet.com K.K. All Rights Reserved.http://www.internet.com/