ASP.NET 2.0 の GridView の例: GridView のデータのページングと並べ替え

 

ここをクリックして TOC に戻ります。

大量のデータを表示する場合は、多くの場合、データの一部のみを表示することをお勧めします。これにより、ユーザーは一度に 10 件程度のレコードをステップ実行できます。 さらに、いずれかの列でデータを並べ替えることができる場合は、エンド ユーザーのエクスペリエンスを向上させることができます。 ASP.NET 1.x でページング可能な双方向の並べ替え可能な DataGrid を作成することは可能でしたが、2 つのイベント ハンドラーを作成し、少なくとも 50 行のコードを記述する必要があります。 良いニュースは、ASP.NET 2.0 では、1 行のコードを記述することなく、ページング可能な双方向の並べ替え可能な DataGrid を作成できることです。

メモ 双方向の並べ替え可能な DataGrid は、データを昇順または降順で並べ替えることができるデータです。 GridView が並べ替え可能な場合、GridView の列ヘッダーはハイパーリンクとしてレンダリングされます。 列のハイパーリンクを初めてクリックすると、データは昇順で並べ替えられます。 同じ列のハイパーリンクをもう一度クリックすると、データは降順で並べ替えられます。

マスター/詳細データの表示と同様に、基になるデータが ObjectDataSource から取得されるページング可能で並べ替え可能な GridView を作成する場合は、データアクセス層に、データの並べ替え方法とページングの詳細を指定する入力パラメーターを持つメソッドが含まれていることを確認する必要があります。 そのため、ページングと並べ替えの 2 つの種類の例を見ていきます。1 つは SqlDataSource コントロールを使用してデータベースから直接データを取得し、もう 1 つは ObjectDataSource を使用して DAL からデータを取得します。

ASP.NET 1.x DataGrid には、データをページングするための 2 つのモード (既定のページングとカスタム ページング) がありました。 どちらのページング モデルでも、ページ開発者は、ページごとに表示するレコードの数と、レコードを表示するページの 0 から始まるインデックスを指定する必要がありました。 既定のページングは、DataGridDataSource プロパティに割り当てられたを通じてページングされるデータの内容全体を持つことによって機能します。 その後、DataGrid によって、表示するレコードの正しいサブセットが決定され、残りは破棄されます。 既定のページングは実装が簡単でしたが、ページングされるすべてのレコードがデータベースから返されていたため、パフォーマンス コストが発生しました。 つまり、 DataGrid が合計 1,000 個のレコードをページングしていて、ページごとに 10 個のレコードが表示されている場合、各ページ要求で 1,000 個のレコードがすべてデータベースから返されますが、適切なレコードは 10 個しか表示されません。

カスタム ページングでは、ページ開発者に、ページングされたレコードの合計数を DataGrid に正確に伝え、ページに表示するレコードの正確なサブセットを返すように要求することで、このパフォーマンスの問題を解決しました。 カスタム ページングでは、ページごとに合計 1,000 件のレコードが表示された場合でも、ページごとに 10 個のレコードのみが表示されている場合、ページアクセスごとにデータベースから取得されるレコードは 10 個のみです。 カスタム ページング モデルのパフォーマンスは向上しましたが、ページ開発者の側でより多くのコードと労力が必要でした。

ASP.NET 2.0 GridView では、ページングの両方のモデルをサポートできますが、ASP.NET 1.x DataGrid のような AllowCustomPaging プロパティはありません。 次の 2 つのセクションでは、 GridView で使用されるページング モデルを SqlDataSource と ObjectDataSource で指定する方法について説明 します

SqlDataSource からのデータのページングと並べ替え

SqlDataSource から取得された GridView のデータのページングと並べ替えは、ASP.NET 2.0 では簡単です。 前のデモと同様に、まず、目的のデータにアクセスする SqlDataSource を追加します。 次に、 GridView を追加します。 GridView のスマート タグには、[ページングを有効にする] と [並べ替えを有効にする] の 2 つのチェック ボックスが含まれています。 並べ替えやページングを有効にするには、適切なチェックボックスをチェックします (図 21 を参照)。 このように簡単です。

メモSqlDataSource には DataSourceMode プロパティがあり、SqlDataSourceDataReader または DataSet を返すかどうかを指定するために設定できます。DataSet は既定値です。 ページング可能な GridView を作成する場合は、 DataSet を返す必要があります。 GridView の並べ替え機能は、DataSet または DataReader でのみ使用できますが、DataReader を返して並べ替える場合は、ストアド プロシージャからデータを取得する必要があります。 さらに、このストアド プロシージャは、並べ替え式を示すパラメーターを受け入れる必要があります。 SqlDataSourceSortParameterName プロパティを使用して、この入力パラメーターの名前を指定します。

Aa479347.gridview_fg21(en-us,MSDN.10).gif

図 21

ASP.NET ページの宣言型構文を次に示します。 ご覧のように、ページング可能な双方向の並べ替え可能な GridView を作成するためにソース コードは必要ありません。

<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" 
  "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<script runat="server">
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Untitled Page</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:SqlDataSource ID="productDataSource" Runat="server" 
         SelectCommand="SELECT [ProductName], [UnitPrice], 
         [UnitsInStock], [QuantityPerUnit] FROM [Products]"
            ConnectionString=
            "<%$ ConnectionStrings:NWConnectionString %>">
        </asp:SqlDataSource>
        <asp:GridView ID=" productsGridView" Runat="server" 
         DataSourceID="productDataSource" AutoGenerateColumns="False"
            AllowSorting="True" BorderWidth="2px" BackColor="White" 
            GridLines="None" CellPadding="3"
            CellSpacing="1" BorderStyle="Ridge" BorderColor="White"
            AllowPaging="True">
            <FooterStyle ForeColor="Black" 
               BackColor="#C6C3C6"></FooterStyle>
            <PagerStyle ForeColor="Black" HorizontalAlign="Right" 
               BackColor="#C6C3C6"></PagerStyle>
            <HeaderStyle ForeColor="#E7E7FF" Font-Bold="True" 
               BackColor="#4A3C8C"></HeaderStyle>
            <Columns>
                <asp:BoundField HeaderText="Product" 
                  DataField="ProductName" SortExpression="ProductName">
                </asp:BoundField>
                <asp:BoundField HeaderText="Unit Price" 
                  DataField="UnitPrice" SortExpression="UnitPrice"
                    DataFormatString="{0:c}">
                    <ItemStyle HorizontalAlign="Right"></ItemStyle>
                </asp:BoundField>
                <asp:BoundField HeaderText="Units In Stock" 
                  DataField="UnitsInStock" 
                  SortExpression="UnitsInStock"
                    DataFormatString="{0:d}">
                    <ItemStyle HorizontalAlign="Right"></ItemStyle>
                </asp:BoundField>
                <asp:BoundField HeaderText="Quantity Per Unit" 
                  DataField="QuantityPerUnit"></asp:BoundField>
            </Columns>
            <SelectedRowStyle ForeColor="White" Font-Bold="True" 
                 BackColor="#9471DE"></SelectedRowStyle>
            <RowStyle ForeColor="Black" BackColor="#DEDFDE"></RowStyle>
        </asp:GridView>
        <i>You are viewing page
        <%=productsGridView.PageIndex + 1%>
        of
        <%=productsGridView.PageCount%>
        </i>
    </div>
    </form>
</body>
</html>

図 22、23、24 は、ページング可能な双方向の並べ替え可能な GridView の動作を示しています。 図 22 は、製品名で昇順に並べ替えられたデータの 1 ページ目を示しています。 図 23 は、製品名で降順に並べられたページ 1 を示しています。 図 24 は、単価で昇順に並べ替えられた 4 ページを示しています。

[単位あたりの数量] 列は、ヘッダーにハイパーリンクが含まれていないという点で、他の列とは異なっていることに注意してください。 つまり、単位あたりの数量でデータを並べ替えることはできません。 列を SortExpression プロパティで並べ替え可能にするかどうかを指定できます。 ASP.NET ページの宣言構文に戻ると、最後の BoundField ([単位あたりの数量] 列) に SortExpression 属性が含まれているのに対し、他のすべての BoundField に存在することがわかります。

Aa479347.gridview_fg22(en-us,MSDN.10).gif

図 22

Aa479347.gridview_fg23(en-us,MSDN.10).gif

図 23

Aa479347.gridview_fg24(en-us,MSDN.10).gif

図 24

GridView の下部には、現在表示されているデータのページと、存在するデータの合計ページ数をエンド ユーザーに通知するテキストが表示されます。 GridView は、表示されているデータの現在のページを指定した 0 から始まる PageIndex プロパティと、使用可能なデータの合計ページ数を示す PageCount プロパティを公開します。 この情報を表示するには、%=...%> 区切り記号を使用して必要なマークアップを<出力するだけで、サーバー側のプロパティ値が出力されます。

<i>You are viewing page
<%=productsGridView.PageIndex + 1%>
of
<%=productsGridView.PageCount%>
</i>

ページング可能な GridView のデータ ソース管理として SqlDataSource を使用することの欠点は、GridView で既定のページング モデルが使用されていることです。 つまり、各ページ要求で 、SqlDataSource は、ページ処理 されるすべての レコードを GridView に返します。 その後、 GridView は、ページごとに表示するレコード数とページ インデックスに基づいて、レコードの正しいサブセットを選択します。 カスタム ページング モデルを実装するには、 ObjectDataSource を使用する必要があります。

ObjectDataSource からのデータのページングと並べ替え

ASP.NET ページ開発者の見込みから、ObjectDataSource からページング可能な双方向の並べ替え可能な GridView を作成することは、SqlDataSource を使用する場合とほぼ同じです。 ObjectDataSource では、既定のページング モデルとカスタム ページング モデルの両方がサポートされています。 ObjectDataSource がページング対象のすべてのデータを返す場合は、既定のページング モデルが使用されます。 カスタム ページング モデルを使用するには、正しいレコードのサブセットのみを返し、ページングするレコードの合計数を指定する必要があります。 すぐにカスタム ページングについて説明しますが、最初に ObjectDataSource で既定のページングを使用する例を見てみましょう。

ページングと並べ替えをサポートするには、データ アクセス層クラスに追加の機能を含める必要があります。 ObjectDataSource からのページング可能な GridView の場合、基になる DAL クラスの SELECT メソッドは 2 つの整数入力を受け入れる必要があります。1 つ目は、返されるレコードの最大数を指定し、もう 1 つは開始レコード インデックスを指定します。 次のコードは、GetProducts() メソッドのオーバーロードされたバージョンを作成することによってページングに使用できるメソッドを含むように ProductDAL クラスを拡張する方法を示しています。 入力パラメーターを受け取っていない元のバージョンでは、新しいバージョンの結果が単に返され、2 つの必須入力パラメーターが受け入れられます。

ProductDAL クラス (Visual Basic)

Imports Microsoft.VisualBasic
Imports System.Configuration
Imports System.Data
Imports System.Data.SqlClient
Imports System.Collections.Generic
Public Class ProductDAL
    Public Shared Function GetProducts() As List(Of Product)
        ' returns a list of Product instances based on the
        ' data in the Northwind Products table
        Return GetProducts(Integer.MaxValue, 0)
    End Function
    Public Shared Function GetProducts(ByVal maximumRows As Integer, _
      ByVal startRowIndex As Integer) As List(Of Product)
        ' returns a list of Product instances based on the
        ' data in the Northwind Products table
        Dim sql As String = "SELECT ProductID, ProductName, " & _
          QuantityPerUnit, UnitPrice, UnitsInStock FROM Products"
        Using myConnection As New _
          SqlConnection(ConfigurationManager.ConnectionStrings( _
         "NWConnectionString").ConnectionString)
            'Place the data in a DataTable
            Dim myCommand As New SqlCommand(sql, myConnection)
            Dim myAdapter As New SqlDataAdapter(myCommand)
            myConnection.Open()
            Dim dt As New DataTable
            myAdapter.Fill(dt)
            Dim results As New List(Of Product)()
            Dim currentIndex As Integer = startRowIndex
            Dim itemsRead As Integer = 0
            Dim totalRecords As Integer = dt.Rows.Count
            While itemsRead < maximumRows AndAlso _
              currentIndex < totalRecords
                Dim product As New Product()
                product.ProductID = _
                 Convert.ToInt32(dt.Rows(currentIndex)("ProductID"))
                product.ProductName = _
                 dt.Rows(currentIndex)("ProductName").ToString()
                product.QuantityPerUnit = _
                 dt.Rows(currentIndex)("QuantityPerUnit").ToString()
                If dt.Rows(currentIndex) _
                  ("UnitPrice").Equals(DBNull.Value) Then
                    product.UnitPrice = 0
                Else
                    product.UnitPrice = _
                 Convert.ToDecimal(dt.Rows(currentIndex)("UnitPrice"))
                End If
                If dt.Rows(currentIndex) _
                 ("UnitsInStock").Equals(DBNull.Value) Then
                    product.UnitsInStock = 0
                Else
                    product.UnitsInStock = _
                Convert.ToInt32(dt.Rows(currentIndex)("UnitsInStock"))
                End If
                results.Add(product)
                itemsRead += 1
                currentIndex += 1
            End While
            myConnection.Close()
            Return results
        End Using
    End Function    
End Class

ProductDAL クラス (C#)

using System;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.Collections.Generic;
/// <summary>
/// Summary description for ProductDAL
/// </summary>
public class ProductDAL
{
    public static List<Product> GetProducts()
    {
        return GetProducts(int.MaxValue, 0);
    }
    public static List<Product> GetProducts(int maximumRows, 
      int startRowIndex)
    {
        return GetProducts(maximumRows, startRowIndex);
    }
    public static List<Product> GetProducts(int maximumRows, 
      int startRowIndex)
    {
        // returns a list of Product instances based on the
        // data in the Northwind Products table
        string sql = @"SELECT ProductID, ProductName, QuantityPerUnit, 
          UnitPrice, UnitsInStock
          FROM Products";
        using (SqlConnection myConnection = new 
          SqlConnection(ConfigurationManager.ConnectionStrings[
          "NWConnectionString"].ConnectionString))
        {
            // Place the data in a DataTable
            SqlCommand myCommand = new SqlCommand(sql, myConnection);
            SqlDataAdapter myAdapter = new SqlDataAdapter(myCommand);
            myConnection.Open();
            DataTable dt = new DataTable();
            myAdapter.Fill(dt);
            List<Product> results = new List<Product>();
            int currentIndex = startRowIndex;
            int itemsRead = 0;
            int totalRecords = dt.Rows.Count;
            while (itemsRead < maximumRows && 
             currentIndex < totalRecords)
            {
                Product product = new Product();
                product.ProductID = 
                  Convert.ToInt32(dt.Rows[currentIndex]["ProductID"]);
                product.ProductName = 
                  dt.Rows[currentIndex]["ProductName"].ToString();
                product.QuantityPerUnit = 
                  dt.Rows[currentIndex]["QuantityPerUnit"].ToString();
                if (dt.Rows[currentIndex]
                 ["UnitPrice"].Equals(DBNull.Value))
                    product.UnitPrice = 0;
                else
                    product.UnitPrice = 
                 Convert.ToDecimal(dt.Rows[currentIndex]["UnitPrice"]);
                if (dt.Rows[currentIndex]
                  ["UnitsInStock"].Equals(DBNull.Value))
                    product.UnitsInStock = 0;
                else
                    product.UnitsInStock = 
                Convert.ToInt32(dt.Rows[currentIndex]["UnitsInStock"]);
                results.Add(product);
                itemsRead++;
                currentIndex++;
            }
            myConnection.Close();
            return results;
        }
    }    
}

製品の正しいサブセットを返す GetProducts(maximumRows, startRowIndex) メソッドのロジックは、むしろ呼び出しです。データベースからすべての製品を取得し、すべての製品のセットから正しい製品インスタンスのリストを作成します。 したがって、このメソッドは 既定のページング に等しいので、ページングするすべてのレコードはデータ ストアから取得されます。ただし、取得されたレコードの総数の小さなサブセットのみが表示されます。

メモ よりインテリジェントなオプションには、キャッシュや手法を使用して、データベースからレコードの適切なサブセットのみを取得する必要があります (詳細については、「 Rob HowardWeb アプリケーションを作成するための 10 個のヒント」のヒント 2 High-Performance を参照してください)。 ObjectDataSource を使用してカスタム ページングを実行するには、ページングされるレコードの合計数を返すメソッドも作成する必要があります。 このメソッドは入力パラメーターを受け取らず、整数を返す必要があります。 その後、 GridView によってこのメソッドが呼び出され、ページングされるレコードの合計数が決定されます。 表示されるデータの特定のサブセットのみが ObjectDataSource から返されるため、この情報はページング コントロールのレンダリングに使用され、 ObjectDataSource によって明示的に提供される必要があります。

ObjectDataSource から並べ替え可能な GridView を作成するには、基になる DAL クラスの SELECT メソッドで、並べ替え順序を指定する文字列パラメーターを受け入れる必要があります。 これを実現するために、並べ替えられた順序ですべてのレコードを返す GetProducts(SortExpression) と、並べ替えられた順序でレコードの特定のページを返す GetProducts(maximumRows、startRowIndex、SortExpression) の 2 つのオーバーロードされた形式の GetProducts() メソッドを作成しました。

ProductDAL クラス (Visual Basic)

Public Class ProductDAL
    Public Shared Function GetProducts() As List(Of Product)
        ' returns a list of Product instances based on the
        ' data in the Northwind Products table
        Return GetProducts(Integer.MaxValue, 0, String.Empty)
    End Function
    Public Shared Function GetProducts(ByVal maximumRows As Integer, _
      ByVal startRowIndex As Integer) As List(Of Product)
        ' returns a list of Product instances based on the
        ' data in the Northwind Products table
        Return GetProducts(maximumRows, startRowIndex, String.Empty)
    End Function
    Public Shared Function GetProducts(ByVal SortExpression As String) _
      As List(Of Product)
        Return GetProducts(Integer.MaxValue, 0, SortExpression)
    End Function
    Public Shared Function GetProducts(ByVal maximumRows As Integer, _
      ByVal startRowIndex As Integer, _
      ByVal SortExpression As String) As List(Of Product)
        ' returns a list of Product instances 
        ' based on the data in the Northwind Products table
        ' returns a particular subset of the data 
        ' ordered by a particular field
        Dim sql As String = "SELECT ProductID, ProductName, " & _
          "QuantityPerUnit, UnitPrice, UnitsInStock FROM Products"
        If SortExpression <> String.Empty Then sql &= _
          " ORDER BY " & SortExpression
        '... The remainder of the code is identical 
        ' to the code in GetProducts(maximumRows, startRowIndex) 
        ' example seen earlier ...
    End Function
End Class

ProductDAL クラス (C#)

public class ProductDAL
{
    public static List<Product> GetProducts()
    {
        return GetProducts(int.MaxValue, 0, string.Empty);
    }
    public static List<Product> GetProducts(int maximumRows, 
      int startRowIndex)
    {
        return GetProducts(maximumRows, startRowIndex, string.Empty);
    }
    public static List<Product> GetProducts(string SortExpression)
    {
        return GetProducts(int.MaxValue, 0, SortExpression);
    }
    public static List<Product> GetProducts(int maximumRows, 
      int startRowIndex, string SortExpression)
    {
        // returns a list of Product instances based on the
        // data in the Northwind Products table
        string sql = @"SELECT ProductID, ProductName, 
          QuantityPerUnit, UnitPrice, UnitsInStock
                        FROM Products";
        if (SortExpression != string.Empty)
            sql += " ORDER BY " + SortExpression;
        //... The remainder of the code is identical to the code 
        // in GetProducts(maximumRows, startRowIndex) example 
        // seen earlier ...
    }
}

ASP.NET ページでデータを適切にページングするには、ページングを正しく機能させるために設定する必要がある ObjectDataSource にいくつかの設定があります。

  • EnablePaging — これを True に設定 します
  • MaximumRowsParameterName - このプロパティは、結果をページするメソッドに最初の整数パラメーターの名前を提供します。 既定値は maximumRows です。 メソッドで別のパラメーター名を使用する場合は、このプロパティでそのパラメーター名を指定する必要があります。
  • StartRowIndexParameterName - MaximumRowsParameterName と同様に、このプロパティ値はページングの 2 番目の整数パラメーター名を指定するという点でです。 既定では startRowIndex なので、コードで別のパラメーター名を使用する場合にのみ、このプロパティを明示的に設定する必要があります。
  • SelectCountMethod - ページングするレコードの合計数を返すメソッドの名前。 (私の例では、メソッド名は TotalNumberOfProducts でした。

並べ替えを適切に行うには、次の 1 つのプロパティを設定する必要があります。

  • SortParameterName : データの並べ替え方法を指定する文字列入力パラメーターの名前。 私の例では 、SortExpressionを使用しました。

次の宣言構文は、すべてがどのように結び付けられているかを示しています。 SqlDataSource を使用してページング可能な双方向の並べ替え可能な GridView を作成する場合と同様に、ObjectDataSource で行うには、ASP.NET ページにコードは必要ありません。 2 つの例のメイン違いは、使用されるデータ ソース 管理 (SqlDataSourceObjectDataSource) と、設定する必要がある ObjectDataSource ページングおよび並べ替えプロパティです。

<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" 
  "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<script runat="server">
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Untitled Page</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:ObjectDataSource ID="productsDataSource" 
          Runat="server" TypeName="ProductDAL" 
          SortParameterName="SortExpression"
            SelectMethod="GetProducts" EnablePaging="True" 
            SelectCountMethod="TotalNumberOfProducts">
        </asp:ObjectDataSource>
        <asp:GridView ID="productsGridView" AllowPaging="True" 
         BorderColor="White" BorderStyle="Ridge"
            CellSpacing="1" CellPadding="3" GridLines="None" 
            BackColor="White" BorderWidth="2px"
            AutoGenerateColumns="False" 
            DataSourceID="productsDataSource" 
            Runat="server" AllowSorting="True">
            <FooterStyle ForeColor="Black" BackColor="#C6C3C6"></FooterStyle>
            <PagerStyle ForeColor="Black" HorizontalAlign="Right" 
             BackColor="#C6C3C6"></PagerStyle>
            <HeaderStyle ForeColor="#E7E7FF" Font-Bold="True" 
             BackColor="#4A3C8C"></HeaderStyle>
            <Columns>
                <asp:BoundField HeaderText="Product" 
                  DataField="ProductName" 
                  SortExpression="ProductName"></asp:BoundField>
                <asp:BoundField HeaderText="Unit Price" 
                  DataField="UnitPrice" SortExpression="UnitPrice"
                    DataFormatString="{0:c}">
                    <ItemStyle HorizontalAlign="Right"></ItemStyle>
                </asp:BoundField>
                <asp:BoundField HeaderText="Units In Stock" 
                    DataField="UnitsInStock" 
                    SortExpression="UnitsInStock"
                    DataFormatString="{0:d}">
                    <ItemStyle HorizontalAlign="Right"></ItemStyle>
                </asp:BoundField>
                <asp:BoundField HeaderText="Quantity Per Unit" 
                   DataField="QuantityPerUnit"></asp:BoundField>
            </Columns>
            <SelectedRowStyle ForeColor="White" 
               Font-Bold="True" 
               BackColor="#9471DE"></SelectedRowStyle>
            <RowStyle ForeColor="Black" BackColor="#DEDFDE"></RowStyle>
        </asp:GridView>
        <i>You are viewing page
        <%=productsGridView.PageIndex + 1%>
        of
        <%=productsGridView.PageCount%>
        </i>
    
    </div>
    </form>
</body>
</html>

出力は、前に調べたデータベースの例と同じです。ページング可能な双方向の並べ替え可能な GridView のスクリーンショットについては、図 22、23、および 24 を参照してください。

次のセクション: GridView 列に画像を表示する

© Microsoft Corporation. All rights reserved.