WebSurfer's Home

トップ > Blog 1   |   ログイン
APMLフィルター

SqlDataSource などのパラメータ

by WebSurfer 2010年9月26日 20:16

データバウンドコントロール (GridView など) からデータソースコントロール (SqlDataSource など) へのパラメータの渡し方について調べたことを書いておきます。

(1) データバウンドコントロール

簡単に言えば、データバウンドコントロールは、DataKeyNames プロパティ、子コントロール、ビューステートなど(他に DataKey などもあるかも)からパラメータ名と値を取得し、Keys, Values, OldValues, NewValues という IDictionary コレクションを作成して、それをデータソースコントロールのパラメータに渡すということだそうです。

詳しくは、MSDN ライブラリ の「データソースコントロールがデータ連結フィールドのパラメーターを作成する方法」に書いてあります。 これによると、IDictionary コレクションは、以下のように各操作(のパラメータ)に渡されているそうです。

IDictionary
コレクション
内容 操作
Values 新しい値(主キー含む) Insert
Keys 元の主キー値 Update, Delete
NewValues 新しい値(主キー含む) Update
OldValues 元の値(主キー除く) Update, Delete

主キーも Update する場合、新しい主キー値は NewValues に含まれるとイベントハンドラのドキュメントに書いてありました。 Insert の時の新しい主キー値がどれに含まれるか、はっきり書いてあるドキュメントは見つけられませんでしたが、Values 以外にはなさそうです。

Keys, Values, OldValues, NewValues には、データバインドコントロールの Deleting, Deleted, Inserting, Inserted, Updating, Updated イベントのハンドラの引数を通じてアクセスできます。 それを使って、データベースに書き込む前の値の検証や HTML エンコードを行ったり、新旧データをログに残したりできるということです。

イベントハンドラのドキュメントで、Deleting, Deleted イベントのハンドラの引数から IDictionary コレクションにアクセスするためのプロパティ名が Keys と Values になっていることがちょっと気になります。 Keys と OldValues のはずなんですが・・・

この Values というのは単なるプロパティ名であって、中身は OldValues であろうと勝手に解釈し、上にリンクを張った MSDN ライブラリの記述は正しいと信じることにしました。(笑)

(2) データソースコントロール

データソースコントロール (SqlDataSource, ObjectDataSource など) 側では、DeleteParameters, InsertParameters, UpdateParameters パラメータコレクションに必要なパラメータが設定され、それにデータバウンドコントロールからのデータが渡されるのは間違いないようです。

ただ、それらのパラメータがどのように作られるか、Keys, Values, OldValues, NewValues との対応がどうなっているかは正直言ってよく分かりません。 想像も含みますが、自分が調べた範囲で分かったことを書いておきます。

(2.1) SqlDataSource

SqlDataSource の場合は、SELECT クエリだけは自分で組み立てるものの、後はウィザード任せで自動生成することがほとんどなので、結果として出来上がったパラメータしか見えないです。

ですが、楽観的同時実行制御を行うか否かによって、ConflictDetection, OldValuesParameterFormatString の設定が変わってきて、それによってできるパラメータが変わってくるだけのようです。

例えば、ウィザードで作った SqlDataSource のパラメータコレクションにあるパラメータと、たぶん内部的に作られる ADO.NET の SqlCommand のパラメータの関係は以下ようになっていると思われます。

<asp:Parameter Name="xxx" Type="Int32" />
    ↓
SqlCommand.Parameters.Add(new SqlParameter("@xxx", SqlDbType.Int))

上記の SqlParameter の Value に、該当する Keys, Values, OldValues, NewValues から自動的に値が渡されるようです(このあたりは外から見えないので、確証はないのですが)。

楽観的同時実行制御なしの場合、デフォルトでは OldValuesParameterFormatString が設定されない(デフォルトで "{0}" になる)ので、パラメータ名が original_xxx にはなりません。この点ちょっと紛らわしいのですが、各パラメータには、Keys, Values, NewValues から正しく値が渡されるようです。例えば、主キーが id、その他のパラメータが name とすると、以下のようになるはずです。

パラメータコレクション IDictionary
コレクション
DeleteParameters id ← Keys
InsertParameters id ← Values
name ← Values
UpdateParameters id ← Keys
name ← NewValues

楽観的同時実行制御オプションを有効にすると、ConflictDetection が "CompareAllValues" に、OldValuesParameterFormatString が "original_{0}" に自動的に設定されます。結果、DELETE, INSERT, UPDATE クエリの WHERE 句に、元の値との相違をチェックするための条件が追加され(例えば、WHERE [xxx] = @original_xxx ... のように)、それに応じてパラメータにも original_xxx が追加されます。この場合は、元の値は original_xxx に、新しい値は xxx に代入されるので分かりやすいです。例えば、主キーが id、その他のパラメータが name とすると、以下のようになるはずです。

2012/6/23 注記追加:下の表の DeleteParameters 列で original_name ← OldValues と書きましたが、Deleting, Deleted イベントのハンドラの引数から OldValues 相当の IDictionary コレクションにアクセスするためのプロパティ名は Values(OldValues ではなくて)になりますので注意してください。

パラメータコレクション IDictionary
コレクション
DeleteParameters original_id ← Keys
original_name ← OldValues
InsertParameters id ← Values
name ← Values
UpdateParameters original_id ← Keys
id ← NewValues
original_name ← OldValues
name ← NewValues

(2.2) ObjectDataSource

SQL Server のテーブルを基に、型付 DataSet + TableAdapter を作った場合、その TableAdapter クラスの中に Select, Insert, Delete, Update メソッドが定義されます。それらのメソッドをベースに ObjectDataSource をウィザードベースで作った場合は、そのメソッドに定義されている引数に合わせてパラメータが作られます。

データバウンドコントロールの Keys, Values, OldValues, NewValues コレクションは、パラメータを通じて、該当する引数に渡されます。ウィザードに任せて TableAdapter と ObjectDataSource を作れば、たぶんほとんどのケースで、渡される Keys, Values, OldValues, NewValues コレクションと、それを受け取るパラメータの間に不整合を生ずることはないはずです。

ただし、自力でメソッドのコードを書く場合や、データソースに主キーがない場合は、以下の点に注意が必要です。

(2.2.1) OldValuesParameterFormatString の設定

ウィザードでデフォルト設定のまま ObjectDataSource を作っていくと、どういう条件になっているのか分かりませんが、楽観的同時実行制御なしの場合でも OldValuesParameterFormatString="original_{0}" の設定がされることがあります。

そうすると、更新もしくは削除操作の際、主キーについては xxx と original_xxx の両方を引数に加えて Update, Delete メソッドを呼び出すようです。

楽観的同時実行制御なしで自力でメソッドのコードを書いた場合、引数に新旧両方の値を定義する必要はなく、普通はたぶん xxx のみしか定義しないと思います。 それゆえ、更新もしくは削除操作の際、"... original_xxx を含む非ジェネリックメソッド 'Update/Delete' が見つかりませんでした。" という例外がスローされ、悩むことになります。

ちょっとくどいかもしれませんが、具体的に、Microsoft ASP.NET のチュートリアル "Creating a Business Logic Layer" のコードを例にとって説明します。

サンプルコードを見ると、DeleteProduct, UpdateProduct メソッドの引数には、主キーとしては productID のみしか定義されていません。

このサンプルコードをベースにして、ObjectDataSource をウィザードで作っていった場合、引数に original_pruductID は定義されていないにもかかわらず、 OldValuesParameterFormatString="original_{0}" が設定されます(自分で試した限りですが)。

そうすると、例えば更新操作を行った場合、"ObjectDataSource 'ObjectDataSource1' では、パラメータ ..., productID, original_productID を含む非ジェネリック メソッド 'UpdateProduct' が見つかりませんでした。" という InvalidOperationException 例外がスローされます。

対応策としては、OldValuesParameterFormatString="original_{0}" を削除するか、使わなくても、xxx と original_xxx の両方を Update, Delete の引数には、定義しておくことです。

(2.2.2) データソースに主キーがない場合

データソースが xml ファイルなどで、主キーが設定されておらず、しかも更新や削除操作のため自力でそのためのクラスを書くような場合は特に注意が必要です。

例としては MSDN ライブラリの「GridView で XML ファイルをデータ ソースとして使いレコードを編集する方法」のような場合です。(そもそも、そのサンプルコードは間違っているようですが)

上記のページの例のように、「XML ファイル操作用のクラス」を作って、それをベースに GridView と ObjectDataSource をウィザードベースで作成するとうまくいきません。

id と name の両方を更新する場合、以下の変更が必要です。(サンプルは id は更新しないという前提で書かれているようですが)

  • GridView に DataKeyNames="id" を追加。そもそも DataKeyNames を定義しないと、主キーが ObjectDataSource に渡されません。
  • ObjectDataSource に OldValuesParameterFormatString="original_{0}" を追加。これがないと id の新旧の区別ができません。(上に、「楽観的同時実行制御なしの場合でも、デフォルトで OldValuesParameterFormatString="original_{0}" の設定がされます。」と書きましたが、何故かこの場合は定義されません。主キーがないから?)
  • GridView で AutoGenerateColumns="False" とし、id と name の BoundField を定義。こうしないと、id 列が TextBox にならず、更新できません。
  • 「XML ファイル操作用のクラス」の UpdateDataSet の引数に original_id を追加。original_id で DataSet の行を検索し、ヒットした行の当該項目を id に書き換えるよう修正する。

上記のリンク先の MSDN ライブラリのコードを修正し、Delete もできるようにしたサンプルを、後日、作成して書き込んでおくことにします。

Tags: ,

ASP.NET

GridView に複数のテーブルを表示

by WebSurfer 2010年9月10日 13:10

あるテーブルを表示している GridView に 1 列追加し、そこに別テーブルからその行に関連する複数のレコード/フィールドを取得して表示するという話です。

結果は以下のような画面になります。MaterialDetails が追加した列です。

実行結果の画面

以下に具体的な例を説明します。

データベースで、「製品」は Products テーブルにて、「原料」は Materials テーブルにて管理されているとします。「製品」に使用されている「原料」の情報は Products や Materials テーブルには埋め込まず、関連を Relations という別テーブルで管理するとします。以下のような感じです。

製品テーブル (Products)
ProductID     int
ProductName   nvarchar(50)
UnitPrice     money

関連テーブル (Relations)
ProductID     int
MaterialID    int

原料テーブル (Materials)
MaterialID    int
MaterialName  nvarchar(50)
SupplierID    int

Products テーブルをベースに作った「製品」一覧の GridView に 1 列追加して、その列に、「製品」に使われている「原料」を表示します。

Materials テーブルから、関連するレコードの MaterialID, MaterialName, SupplierID をRelations テーブルを基に抽出し、追加した列に表示します。

製品 X には原料 a, b が、製品 Y には原料 a, e, f, h が使われているというように、追加した列に表示する Materials テーブルのレコード数は各行で一定ではありません。それに対応するための工夫が必要です。

具体的な手順は、以下のようになります。「原料」で表示するのが 1 フィールドだけでよいということであれば、もう少し簡単にできますが、基本的には以下の手順と同様です。

(1) Products の 型付 DataSet + TableAdapter

ソリューションにデータセット(xsd ファイル)を追加します。それにツールボックスから TableAdapter をドラッグ&ドロップします。

自動的に「TableAdapter 構成ウィザード」が起動しますので、そのウィザードを利用して Products テーブル用の型付 DataSet + TableAdapter を作成します。

基になる SELECT クエリは下記のようにします。

SELECT ProductID, ProductName, UnitPrice
FROM   Products

ウィザードが完了したら xsd ファイルを保存してください。その後、デザイナ画面のテーブル部分を右クリックして、[追加]→[列]で MaterialDetails 列を追加します。型はデフォルトで String になるはずです。

(2) Materials の型付 DataSet + TableAdapter

上記と同じ xsd ファイルの画面にツールボックスからもう一つ TableAdapter をドラッグ&ドロップし、クエリビルダで Materials テーブルと Relations テーブルの二つを追加します。

基になる SELECT クエリは下記のようにし、ウィザードを完了させます。

SELECT m.MaterialID, m.MaterialName, m.SupplierID
FROM   Materials AS m
       INNER JOIN Relations AS r
       ON m.MaterialID = r.MaterialID
WHERE  (r.ProductID = @ProductID)

上記 (1), (2) の結果は、以下の画面のようになります。

型付 DataSet + TableAdapter のデザイン画面

(3) GetProductsWithMaterials メソッド

ソリューションにクラスファイルを追加します。Products, Materials テーブルから必要なデータを抽出し、上記 (1) で作った型付 DataTable を初期化して返すメソッドを作成し、クラスファイルに実装します。

Products テーブルの TableAdapter を拡張する形で partial class にしてください。以下のような感じです。

using System;
using System.IO;
using System.ComponentModel;

namespace ProductsDataSetTableAdapters
{
  public partial class ProductsTableAdapter
  {
    [DataObjectMethod(DataObjectMethodType.Select, true)]
    public ProductsDataSet.ProductsDataTable GetProductsWithMaterials()
    {
      ProductsDataSet.ProductsDataTable prodTable = this.GetData();
      MaterialsTableAdapter adapter = new MaterialsTableAdapter();
      foreach (ProductsDataSet.ProductsRow row in prodTable.Rows)
      {
        ProductsDataSet.MaterialsDataTable mtrlTable = 
          adapter.GetData(row.ProductID);
        StringWriter writer = new StringWriter();
        mtrlTable.WriteXml(writer);
        row.MaterialDetails = writer.ToString();
      }
      return prodTable;
    }
  }
}

(4) aspx ファイル

データを表示する Web ページ(aspx ファイル)を作成します。ObjectDataSource と GridView を利用した例は下記の通りです。MaterialDetails 列の xml データは GridView の RowDataBound イベントで適宜書き換えます。

この例では、xml データを DataTable に戻して、GridView の中にもう一つ GridView を作って表示しています。GridView を使わず、文字列で表示するなど、別の方法も検討してみてください。

<%@ Page Language="C#" %>
<%@ Import Namespace="System.IO" %>
<%@ Import Namespace="System.Data" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">

  protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
  {
    if (e.Row.RowType == DataControlRowType.DataRow)
    {
      string xmlMaterialDetails = 
        (string)((DataRowView)e.Row.DataItem)["MaterialDetails"];
      StringReader reader = new StringReader(xmlMaterialDetails);
      ProductsDataSet.MaterialsDataTable table = 
        new ProductsDataSet.MaterialsDataTable();
      table.ReadXml(reader);
      GridView gv = new GridView();
      gv.DataSource = table;
      e.Row.Cells[3].Controls.Clear();
      e.Row.Cells[3].Controls.Add(gv);
      gv.DataBind();
    }
  }
</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
  <title></title>
</head>
<body>
  <form id="form1" runat="server">
  <div>
    <asp:ObjectDataSource ID="ObjectDataSource1" 
      runat="server" 
      OldValuesParameterFormatString="original_{0}" 
      SelectMethod="GetProductsWithMaterials" 
      TypeName="ProductsDataSetTableAdapters.ProductsTableAdapter">
    </asp:ObjectDataSource>
    <asp:GridView ID="GridView1" 
      runat="server" 
      AutoGenerateColumns="False" 
      DataKeyNames="ProductID" 
      DataSourceID="ObjectDataSource1" 
      OnRowDataBound="GridView1_RowDataBound">
      <Columns>
        <asp:BoundField DataField="ProductID" 
          HeaderText="ProductID" 
          InsertVisible="False" 
          ReadOnly="True" 
          SortExpression="ProductID" />
        <asp:BoundField DataField="ProductName" 
          HeaderText="ProductName" 
          SortExpression="ProductName" />
        <asp:BoundField DataField="UnitPrice" 
          HeaderText="UnitPrice" 
          SortExpression="UnitPrice" />
        <asp:BoundField DataField="MaterialDetails" 
          HeaderText="MaterialDetails" 
          SortExpression="MaterialDetails" />
      </Columns>
    </asp:GridView>
  </div>
  </form>
</body>
</html>

以上、ちょっと凝ったことをしましたが、「製品」:「原料」の関係が 1:1 もしくは 1:n (n=一定) の関係なら、3 つのテーブルを INNER JOIN した SELECT クエリをベースに、SqlDataSource と ListView で表示した方が簡単だと思います。

Tags: , ,

ASP.NET

ObjectDataSource でページング

by WebSurfer 2010年8月26日 12:00

DB のレコード一覧を表示する場合、レコード数が多い場合はページングが必要になってきます。

SqlDataSource を使って、ウィザードベースでクエリなどを設定していけば、コードを一行も書くことなく簡単にページング機能を実装できます。

しかしながら、ウィザードベースで実装した場合は、ページを切り替えるたびに全レコードを取得し、そのページの当該部分のみを表示するという動作になります。

レコード数が多い場合、ページングの都度全レコードを取得するのは負荷が大きく、できれば避けたい操作です。

ちなみに、先の記事 カスタムページャー で紹介した Repeater とカスタムページャーを使用したページングではそのあたりは考慮してあります。

今回は、先の記事と同等な内容を、ObjectDataSource と ListView を使って実現する例を書いてみます。実行結果は以下のようになります。

ListVie でのページング

ポイントは、先の記事のようなストアドプロシージャを使うのではなくて、必要なレコードのみ DB から取得するクラス/メソッドを実装して、それらを ObjectDataSource で定義されているプロパティに設定するというところです。

加えて、出来るだけ ObjectDataSource と ListView が持つページングの機能を利用し、自力でコードは書かない(上記のクラス/メソッドを除く)ということもあります。

まず、型付 DataSet + TableAdapter(xsd ファイル)を Visual Studio のウィザードを利用して作成します。

Microsoft が提供しているサンプルデータベース Northwind の Products テーブルを利用します。ウィザードに従って進めていくと xsd ファイルが作られ、これをベースに 型付 DataSet + TableAdapter のコードが自動生成されます。

xsd ファイルを開くと、以下のように表示されるはずです。

xsd ファイルの作成

自動生成されたコードは、Web アプリケーションプロジェクトの場合は xsd ファイルの直下に、Web サイトプロジェクトの場合は Temporary ASP.NET Files フォルダ内にあります。

この TableAdapter コードを partial class を使って拡張して、必要なレコードのみ DB から取得するためのクラス/メソッドを実装します。

以下のようになります。GetDataByIndex メソッドの引数名 startRowIndex, maximumRowsは、ObjectDataSource がデフォルトでその名前を参照していますので、そのまま使うのが面倒がないです(変更する場合は MaximumRowsParameterName プロパティと StartRowIndexParameterName プロパティに変更後の引数名を設定してください)。名前空間名、クラス名は、自動生成されたコードを参照してください。

using System;
using System.Data;
using System.Configuration;
using System.Data.SqlClient;
using System.ComponentModel;

namespace ProductsDataSetTableAdapters
{
  public partial class ProductsTableAdapter
  {
    [DataObjectMethod(DataObjectMethodType.Select, true)]
    public ProductsDataSet.ProductsDataTable GetDataByIndex(int startRowIndex, int maximumRows)
    {
      SqlDataAdapter adapter;
      string query = String.Format(
        "SELECT * " +
          "FROM (" + 
             "SELECT *, ROW_NUMBER() OVER (ORDER BY [ProductID] ASC) AS rownum " + 
             "FROM [Products]) AS DerivedTable " +
          "WHERE rownum BETWEEN {0} AND {1} " +
          "ORDER BY [ProductID] ASC",
           startRowIndex + 1, maximumRows + startRowIndex);
      adapter = new SqlDataAdapter(query, this.Connection);

      ProductsDataSet dataset = new ProductsDataSet();
      adapter.Fill(dataset.Products);
      return dataset.Products;
    }

    public int GetNumberOfMessages()
    {
      SqlCommand command;
      command = 
        new SqlCommand("SELECT COUNT(*) FROM [Products]", this.Connection);
      this.Connection.Open();
      int rows = (int)command.ExecuteScalar();
      this.Connection.Close();
      return rows;
    }
  }
}

最後に、ObjectDataSource と ListView を実装した aspx ページを作成します。コードは以下のようになります。

<%@ Page Language="C#" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">

</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
  <title></title>
  <style type="text/css">
    table.style1
    {
      border-style: solid;
      border-width: 2px;
      border-color: Black;
      text-align: center;
      border-collapse: collapse;
    }
       
    table.style1 th
    {
      border-style: solid;
      border-width: 2px 1px 2px 1px;
      border-color: Black;
      background-color: #6699FF;
      color: #FFFFFF;
    }
        
    table.style1 td
    {
      border-style: solid;
      border-width: 1px;
      border-color: Black;        
    }
        
    .alternate
    {
      background-color: #CCFFFF;
    }  
  </style>
</head>
<body>
  <form id="form1" runat="server">
  <div>
    <asp:ObjectDataSource ID="ObjectDataSource1" 
      runat="server" 
      SelectMethod="GetDataByIndex" 
      SelectCountMethod="GetNumberOfMessages" 
      EnablePaging="True"             
      TypeName="ProductsDataSetTableAdapters.ProductsTableAdapter">
    </asp:ObjectDataSource>
    <asp:ListView ID="ListView1" 
      runat="server" 
      DataKeyNames="ProductID" 
      DataSourceID="ObjectDataSource1" 
      EnableModelValidation="True">
      <LayoutTemplate>
        <table id="Table1" runat="server" class="style1">
          <tr id="Tr1" runat="server" style="">
            <th id="Th1" rowspan="2" runat="server">ProductID</th>
            <th id="Th2" colspan="7" runat="server">ProductName</th>
            <th id="Th3" rowspan="2" runat="server">Discontinued</th>
          </tr>
          <tr>
            <th id="Th4" runat="server">SupplierID</th>
            <th id="Th5" runat="server">CategoryID</th>
            <th id="Th6" runat="server">QuantityPerUnit</th>
            <th id="Th7" runat="server">UnitPrice</th>
            <th id="Th8" runat="server">UnitsInStock</th>
            <th id="Th9" runat="server">UnitsOnOrder</th>
            <th id="Th10" runat="server">ReorderLevel</th>
          </tr>                                
          <tr ID="itemPlaceholder" runat="server">
          </tr>
        </table>
      </LayoutTemplate>
      <AlternatingItemTemplate>
        <tr class="alternate">
          <td rowspan="2">
            <asp:Label ID="ProductIDLabel" 
              runat="server" 
              Text='<%# Eval("ProductID") %>' />
          </td>
            <td colspan="7">
            <asp:Label ID="ProductNameLabel" 
              runat="server" 
              Text='<%# Eval("ProductName") %>' />
          </td>
          <td rowspan="2">
            <asp:CheckBox ID="DiscontinuedCheckBox" 
              runat="server" 
              Checked='<%# Eval("Discontinued") %>' 
              Enabled="false" />
          </td>
        </tr>
        <tr class="alternate">
          <td>
            <asp:Label ID="SupplierIDLabel" 
              runat="server" 
              Text='<%# Eval("SupplierID") %>' />
          </td>
          <td>
            <asp:Label ID="CategoryIDLabel" 
              runat="server" 
              Text='<%# Eval("CategoryID") %>' />
          </td>
          <td>
            <asp:Label ID="QuantityPerUnitLabel" 
              runat="server" 
              Text='<%# Eval("QuantityPerUnit") %>' />
          </td>
          <td>
            <asp:Label ID="UnitPriceLabel" 
              runat="server" 
              Text='<%# Eval("UnitPrice") %>' />
          </td>
          <td>
            <asp:Label ID="UnitsInStockLabel" 
              runat="server" 
              Text='<%# Eval("UnitsInStock") %>' />
          </td>
          <td>
            <asp:Label ID="UnitsOnOrderLabel" 
              runat="server" 
            Text='<%# Eval("UnitsOnOrder") %>' />
          </td>
            <td>
            <asp:Label ID="ReorderLevelLabel" 
               runat="server" 
               Text='<%# Eval("ReorderLevel") %>' />
          </td>
        </tr>
      </AlternatingItemTemplate>
      <ItemTemplate>
        <tr>
          <td rowspan="2">
            <asp:Label ID="ProductIDLabel" 
              runat="server" 
              Text='<%# Eval("ProductID") %>' />
          </td>
          <td colspan="7">
          <asp:Label ID="ProductNameLabel" 
            runat="server" 
            Text='<%# Eval("ProductName") %>' />
          </td>
            <td rowspan="2">
              <asp:CheckBox ID="DiscontinuedCheckBox" 
                runat="server" 
                Checked='<%# Eval("Discontinued") %>' 
                Enabled="false" />
            </td>
        </tr>
        <tr>
         <td>
           <asp:Label ID="Label1" 
             runat="server" 
             Text='<%# Eval("SupplierID") %>' />
         </td>
         <td>
           <asp:Label ID="Label2" 
             runat="server" 
             Text='<%# Eval("CategoryID") %>' />
         </td>
         <td>
           <asp:Label ID="Label3" 
             runat="server" 
             Text='<%# Eval("QuantityPerUnit") %>' />
         </td>
         <td>
           <asp:Label ID="Label4" 
             runat="server" 
             Text='<%# Eval("UnitPrice") %>' />
         </td>
         <td>
           <asp:Label ID="Label5" 
             runat="server" 
             Text='<%# Eval("UnitsInStock") %>' />
         </td>
         <td>
           <asp:Label ID="Label6" 
             runat="server" 
             Text='<%# Eval("UnitsOnOrder") %>' />
         </td>
         <td>
           <asp:Label ID="Label7" runat="server" 
              Text='<%# Eval("ReorderLevel") %>' />
         </td>
       <tr>
      </ItemTemplate>
    </asp:ListView>
    <asp:DataPager ID="DataPager1" 
      runat="server" 
      PageSize="7" 
      PagedControlID="ListView1">
      <Fields>
        <asp:NextPreviousPagerField 
          ButtonType="Link" 
          ShowFirstPageButton="True" 
          ShowNextPageButton="False" 
          ShowPreviousPageButton="False" 
          FirstPageText="&lt;&lt;最初" />
        <asp:NumericPagerField 
          ButtonCount="5"
          PreviousPageText="&lt;前の 5 ページ"
          NextPageText="次の 5 ページ&gt;"/>
        <asp:NextPreviousPagerField 
          ButtonType="Link" 
          ShowLastPageButton="True" 
          ShowNextPageButton="False" 
          ShowPreviousPageButton="False" 
          LastPageText="最後&gt;&gt;" />
      </Fields>
    </asp:DataPager>
  </div>
  </form>
</body>
</html>

先の記事の方法と今回の記事の方法とで、どちらが簡単かと言えば、正直言ってどっちもどっちって感じです。

Tags: , ,

Paging

About this blog

2010年5月にこのブログを立ち上げました。主に ASP.NET Web アプリ関係の記事です。

Calendar

<<  2024年5月  >>
2829301234
567891011
12131415161718
19202122232425
2627282930311
2345678

View posts in large calendar