GridView のフッターに概要情報を表示する (C#)
集計情報は、多くの場合、レポートの下部にある集計行に表示されます。 GridView コントロールを使用すると、フッター行を追加し、プログラムによってそのセルに集計データを挿入することができます。 このチュートリアルでは、このフッター行に集計データを表示する方法について説明します。
はじめに
ユーザーが確認したいのは、各製品の価格、在庫単位数、注文単位数、再注文レベルだけでなく、平均価格、在庫単位の合計数といった集計情報も含まれる場合が多いです。 このような集計情報は、多くの場合、レポートの下部にある集計行に表示されます。 GridView コントロールを使用すると、フッター行を追加し、プログラムによってそのセルに集計データを挿入することができます。
このタスクには、次の 3 つの課題が立ちはだかります。
- フッター行を表示するために GridView を構成する
- 集計データを算出する。つまり、平均価格や在庫単位の合計数をどのように算出するか
- 集計データをフッター行の適切なセルに挿入する
このチュートリアルでは、これらの課題をどう克服するかについて説明していきます。 具体的には、カテゴリをドロップダウン リストとして表示し、そこで選択したカテゴリの製品を GridView に一覧表示するページを作成します。 この GridView には、そのカテゴリに含まれる製品の平均価格と、在庫単位数および注文単位数それぞれの合計数を示すフッター行を表示します。
図 1: 集計情報が GridView のフッター行に表示されています (クリックするとフルサイズの画像が表示されます)
このチュートリアルは、カテゴリから製品のマスター/詳細インターフェイスを使用しているため、前段となる「DropDownList コントロールと GridView を使用したマスター/詳細フィルター処理」チュートリアルで説明した概念を前提として構成されています。 もし、以前のチュートリアルをまだ行っていない場合は、このチュートリアルを続ける前にまずはそちらをご覧ください。
手順 1: カテゴリ用 DropDownList と製品 GridView を追加する
GridView のフッターに集計情報を追加する前に、まずはシンプルにマスター/詳細レポートを作成しましょう。 この最初の手順を完了したら、集計データを含める方法について見ていきます。
まず、CustomFormatting
フォルダーの SummaryDataInFooter.aspx
ページを開きます。 DropDownList コントロールを追加し、ID
を Categories
に設定します。 次に、DropDownList のスマート タグから [データ ソースの選択] リンクをクリックし、CategoriesBLL
クラスの GetCategories()
メソッドを呼び出す CategoriesDataSource
という名前の新しい ObjectDataSource を追加します。
図 2: CategoriesDataSource
という名前の新しい ObjectDataSource を追加します (クリックするとフルサイズの画像が表示されます)
図 3: ObjectDataSource で CategoriesBLL
クラスの GetCategories()
メソッドを呼び出します (クリックするとフルサイズの画像が表示されます)
ObjectDataSource を構成すると、DropDownList のデータ ソース構成ウィザードに自動で戻ります。このウィザードでは、表示するデータ フィールドの値と、DropDownList の ListItem
の値に対応するデータ フィールドの値を指定する必要があります。 CategoryName
フィールドを表示し、CategoryID
を値として使用します。
図 4: ListItem
の Text
および Value
として、それぞれ CategoryName
フィールドと CategoryID
フィールドを使用します (クリックするとフルサイズの画像が表示されます)
この時点で、システム内のカテゴリを一覧表示する DropDownList (Categories
) ができました。 次に、選択したカテゴリに含まれる製品を一覧表示する GridView を追加する必要があります。 ただし、続行する前に、DropDownList のスマート タグから [AutoPostBack を有効にする] チェックボックスをオンにします。 「DropDownList コントロールと GridView を使用したマスター/詳細フィルター処理」のチュートリアルの説明にあるように、DropDownList の AutoPostBack
プロパティを true
に設定すると、DropDownList の値が変更されるたびにページがポストバックされるようになります。 これにより GridView が更新されるため、新しく選択したカテゴリの製品が表示されます。 AutoPostBack
プロパティが false
(既定値) に設定されていると、カテゴリを変更してもポストバックが発生しないため、製品一覧は更新されません。
図 5: DropDownList のスマート タグの [AutoPostBack を有効にする] チェックボックスをオンにします (クリックするとフルサイズの画像が表示されます)
選択したカテゴリの製品を表示するために、GridView コントロールをページに追加します。 GridView の ID
を ProductsInCategory
に設定し、それを ProductsInCategoryDataSource
という名前の新しい ObjectDataSource にバインドします。
図 6: ProductsInCategoryDataSource
という名前の新しい ObjectDataSource を追加します (クリックするとフルサイズの画像が表示されます)
ProductsBLL
クラスの GetProductsByCategoryID(categoryID)
メソッドを呼び出すように ObjectDataSource を構成します。
図 7: ObjectDataSource で GetProductsByCategoryID(categoryID)
メソッドを呼び出します (クリックするとフルサイズの画像が表示されます)
GetProductsByCategoryID(categoryID)
メソッドは入力パラメーターを受け取るので、ウィザードの最後の手順ではパラメーター値のソースを指定します。 選択したカテゴリの製品を表示するには、Categories
DropDownList からパラメーターをプルします。
図 8: 選択したカテゴリの DropDownList から categoryID
パラメーター値を取得します (クリックするとフルサイズの画像が表示されます)
ウィザードを完了した時点では、GridView に各製品プロパティの BoundField が含まれます。 これらの BoundField をクリーンアップして、BoundField ProductName
、UnitPrice
、UnitsInStock
、UnitsOnOrder
のみが表示されるようにしましょう。 残りの BoundField にフィールド レベルの設定を自由に追加できます (UnitPrice
を通貨として書式設定するなど)。 これらの変更を行うと、GridView の宣言マークアップは次のようになります。
<asp:GridView ID="ProductsInCategory" runat="server"
AutoGenerateColumns="False" DataKeyNames="ProductID"
DataSourceID="ProductsInCategoryDataSource" EnableViewState="False">
<Columns>
<asp:BoundField DataField="ProductName" HeaderText="Product"
SortExpression="ProductName" />
<asp:BoundField DataField="UnitPrice" DataFormatString="{0:c}"
HeaderText="Price"
HtmlEncode="False" SortExpression="UnitPrice">
<ItemStyle HorizontalAlign="Right" />
</asp:BoundField>
<asp:BoundField DataField="UnitsInStock"
HeaderText="Units In Stock" SortExpression="UnitsInStock">
<ItemStyle HorizontalAlign="Right" />
</asp:BoundField>
<asp:BoundField DataField="UnitsOnOrder"
HeaderText="Units On Order" SortExpression="UnitsOnOrder">
<ItemStyle HorizontalAlign="Right" />
</asp:BoundField>
</Columns>
</asp:GridView>
この時点で、選択したカテゴリに含まれる製品の名前、単価、在庫単位数、注文単位数を表示する、完全に機能するマスター/詳細レポートができています。
図 9: 選択したカテゴリの DropDownList から categoryID
パラメーター値を取得します (クリックするとフルサイズの画像が表示されます)
手順 2: GridView にフッターを表示する
GridView コントロールを使用すると、ヘッダー行とフッター行の両方を表示できます。 これらの行はそれぞれ ShowHeader
プロパティと ShowFooter
プロパティの値に応じて表示されます。それぞれ、ShowHeader
の規定値は true
、ShowFooter
の既定値は false
です。 GridView にフッターを含めるには、ShowFooter
プロパティを true
に設定します。
図 10: GridView の ShowFooter
プロパティを true
に設定します (クリックするとフルサイズの画像が表示されます)
フッター行には、GridView で定義したフィールドごとにセルが表示されます。ただし、これらのセルは既定では空です。 ブラウザーで進行状況を確認してみましょう。 ShowFooter
プロパティが true
に設定されているため、GridView には空のフッター行が含まれています。
図 11: GridView にフッター行が含まれるようになりました (クリックするとフルサイズの画像が表示されます)
図 11 のフッター行の背景は白いため、目立っていません。 そこで、背景色を濃い赤色に指定する FooterStyle
CSS クラスを Styles.css
で作成し、DataWebControls
テーマの GridView.skin
スキン ファイルを構成して、この CSS クラスを GridView の FooterStyle
にある CssClass
プロパティに割り当ててみましょう。 スキンとテーマをブラッシュアップする必要がある場合は、ObjectDataSource でデータを表示する方法に関するチュートリアルを参照してください。
まず、次の CSS クラスを Styles.css
に追加します。
.FooterStyle
{
background-color: #a33;
color: White;
text-align: right;
}
FooterStyle
CSS クラスのスタイルと HeaderStyle
クラスのスタイルは似ていますが、HeaderStyle
の背景色の方が少し濃く、テキストは太字で表示されています。 さらに、フッター内のテキストは右揃えですが、ヘッダーのテキストは中央揃えになっています。
次に、この CSS クラスを GridView のすべてのフッターに関連付けるには、DataWebControls
テーマの GridView.skin
ファイルを開き、FooterStyle
の CssClass
プロパティを設定します。 追加後、ファイルのマークアップは次のようになります。
<asp:GridView runat="server" CssClass="DataWebControlStyle">
<AlternatingRowStyle CssClass="AlternatingRowStyle" />
<RowStyle CssClass="RowStyle" />
<HeaderStyle CssClass="HeaderStyle" />
<FooterStyle CssClass="FooterStyle" />
<SelectedRowStyle CssClass="SelectedRowStyle" />
</asp:GridView>
以下のスクリーンショットが示すように、この変更によってフッターがより目立つようになりました。
図 12: GridView のフッター行に赤色の背景色が追加されました (クリックするとフルサイズの画像が表示されます)
手順 3: 集計データを算出する
GridView のフッターが表示できるようになったので、次の課題は、集計データの算出方法です。 この集計情報を計算するには、次の 2 つの方法があります。
SQL クエリを使用することで、データベースに追加のクエリを発行し、特定のカテゴリの集計データを計算することができます。 SQL には、どのデータを集計するかを指定できる
GROUP BY
句とともに、多くの集計関数が含まれています。 次の SQL クエリを実行すると、必要な情報が返されます。SELECT CategoryID, AVG(UnitPrice), SUM(UnitsInStock), SUM(UnitsOnOrder) FROM Products WHERE CategoryID = categoryID GROUP BY CategoryID
もちろん、このクエリは
SummaryDataInFooter.aspx
ページから直接発行するのではなく、ProductsTableAdapter
とProductsBLL
にメソッドを作成して発行します。データに基づくカスタム書式設定に関するチュートリアルの説明にあるように、GridView にデータを追加するたびに情報を計算するようにします。GridView の
RowDataBound
イベント ハンドラーは、データバインドされた後、GridView に行が追加されるたびに一度だけ発生します。 このイベントのイベント ハンドラーを作成することで、集計する値の累計を得ることができます。 最後のデータ行が GridView にバインドされると、合計と平均を計算するために必要な情報が得られます。
データベースへのアクセス回数を減らすことができるだけでなく、データ アクセス レイヤーとビジネス ロジック レイヤーに集計機能を実装する手間が省けるので、私は通常 2 番目のアプローチを採用していますが、どちらの方法でも問題ありません。 このチュートリアルでは 2 番目のオプションを使用し、RowDataBound
イベント ハンドラーを用いて累計を追跡してみましょう。
デザイナーで GridView を選択し、プロパティ ウィンドウの稲妻アイコンをクリックしてから RowDataBound
イベントをダブルクリックして、GridView の RowDataBound
イベント ハンドラーを作成します。 これにより、SummaryDataInFooter.aspx
ページの分離コード クラスに ProductsInCategory_RowDataBound
という名前の新しいイベント ハンドラーが作成されます。
protected void ProductsInCategory_RowDataBound
(object sender, GridViewRowEventArgs e)
{
}
累計値を保持するには、イベント ハンドラーのスコープ外で変数を定義する必要があります。 次の 4 つのページレベルの変数を作成します。
decimal
型の_totalUnitPrice
int
型の_totalNonNullUnitPriceCount
int
型の_totalUnitsInStock
int
型の_totalUnitsOnOrder
次に、RowDataBound
イベント ハンドラーで検出されたデータ行ごとに、これら 3 つの変数をインクリメントするコードを記述します。
// Class-scope, running total variables...
decimal _totalUnitPrice = 0m;
int _totalNonNullUnitPriceCount = 0;
int _totalUnitsInStock = 0;
int _totalUnitsOnOrder = 0;
protected void ProductsInCategory_RowDataBound(object sender,
GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
// Reference the ProductsRow via the e.Row.DataItem property
Northwind.ProductsRow product =
(Northwind.ProductsRow)
((System.Data.DataRowView)e.Row.DataItem).Row;
// Increment the running totals (if they are not NULL!)
if (!product.IsUnitPriceNull())
{
_totalUnitPrice += product.UnitPrice;
_totalNonNullUnitPriceCount++;
}
if (!product.IsUnitsInStockNull())
_totalUnitsInStock += product.UnitsInStock;
if (!product.IsUnitsOnOrderNull())
_totalUnitsOnOrder += product.UnitsOnOrder;
}
}
RowDataBound
イベント ハンドラーでは、まず、扱っている対象が DataRow であることの確認が行われます。 この確認が終わると、e.Row
の GridViewRow
オブジェクトにバインドされた Northwind.ProductsRow
インスタンスが変数 product
に格納されます。 次に、累計値を示す変数が、現在の製品の該当値 (データベース NULL
値が含まれていないと想定) でインクリメントされます。 平均値はこれら 2 つの数値の商であるため、実行中の UnitPrice
の合計とNULL
UnitPrice
以外のレコードの数の両方を追跡します。
手順 4: フッターに集計データを表示する
集計データの合算を出すことができたので、最後の手順は GridView のフッター行に表示することです。 このタスクも、RowDataBound
イベント ハンドラーを使用してプログラムで実行できます。 RowDataBound
イベント ハンドラーは、フッター行を含め、GridView にバインドされている "すべての" 行に対して発生することを思い出してください。 そのため、次のコードを使用することで、イベント ハンドラーを拡張し、フッター行にデータを表示することができます。
protected void ProductsInCategory_RowDataBound
(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
... Increment the running totals ...
}
else if (e.Row.RowType == DataControlRowType.Footer)
{
... Display the summary data in the footer ...
}
}
フッター行が GridView に追加されるのはすべてのデータ行が追加された後になるため、フッターに集計データを表示する準備ができる頃には、累計値の計算は確実に完了しているといえます。 最後の手順では、フッターのセルにこれらの値を設定します。
特定のフッター セルにテキストを表示するには、e.Row.Cells[index].Text = value
を使用します。ここで、Cells
のインデックスは 0 から始まります。 次のコードは、平均価格 (合計価格を製品数で割った値) を計算し、GridView の適切なフッター セルに在庫単位数と注文単位数の合計と共に表示します。
protected void ProductsInCategory_RowDataBound
(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
... <i>Increment the running totals</i> ...
}
else if (e.Row.RowType == DataControlRowType.Footer)
{
// Determine the average UnitPrice
decimal avgUnitPrice = _totalUnitPrice / (decimal) _totalNonNullUnitPriceCount;
// Display the summary data in the appropriate cells
e.Row.Cells[1].Text = "Avg.: " + avgUnitPrice.ToString("c");
e.Row.Cells[2].Text = "Total: " + _totalUnitsInStock.ToString();
e.Row.Cells[3].Text = "Total: " + _totalUnitsOnOrder.ToString();
}
}
図 13 は、このコードが追加された後のレポートを示しています。 ToString("c")
により、平均価格の集計情報が通貨のように書式設定されていることに注目してください。
図 13: GridView のフッター行に赤色の背景色が追加されました (クリックするとフルサイズの画像が表示されます)
まとめ
集計データの表示はレポートに一般的に求められるものですが、GridView コントロールを使用すると、このような情報をフッター行に簡単に含めることができます。 フッター行は、GridView の ShowFooter
プロパティが true
に設定されていると表示され、セル内のテキストは RowDataBound
イベント ハンドラーを用いることでプログラムによって設定できます。 集計データの計算は、データベースに対して再度クエリを実行するか、ASP.NET ページの分離コード クラスのコードを使用して集計データをプログラムで計算することによって行うことができます。
このチュートリアルで、GridView、DetailsView、FormView コントロールを使ったカスタム書式設定の説明を終わります。 次回のチュートリアルでは、これら同じコントロールを使用してデータを挿入、更新、削除する方法に関する説明を開始します。
プログラミングに満足!
著者について
7 冊の ASP/ASP.NET 書籍の著者であり、 4GuysFromRolla.comの創設者である Scott Mitchell は、1998 年から Microsoft Web テクノロジに取り組んでいます。 Scott は、独立したコンサルタント、トレーナー、ライターとして働いています。 彼の最新の著書は Sams Teach Yourself ASP.NET 2.0 in 24 Hoursです。 にアクセスするか、ブログを使用して にアクセスmitchell@4GuysFromRolla.comできます。これは でhttp://ScottOnWriting.NET見つけることができます。