SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

japan.internet.com翻訳記事

.NET データ処理に役立つ26のヒント(前編)

.NETにおけるデータ管理のテクニック

ヒント6:ASP.NET 2.0のGridViewの概要

 ブラウザベースのデータベースアプリケーションでは、多くの場合、GridViewコントロールの機能を利用します。GridViewコントロールは、DataGridコントロールの後継にあたる、ASP.NET 2.0の新機能です。Windowsフォーム環境からWebフォーム環境に移ってきた開発者は、両プラットフォーム間でGridViewコントロールが大きく異なることに気付くはずです。ヒント6~9では、その一般的な機能について説明します。

 図2は、ASP.NETの基本的なGridViewの例です。この例では、Northwindデータベースからデータを取得し、結果のデータセットにGridViewをバインドします。そして、列、配置、書式を定義して、運賃が100.00ドルを超える行を黄色で表示します。

図2 ASP.NET 2.0の基本的なGridView
図2 ASP.NET 2.0の基本的なGridView

 この実装には、次の5つの手順を踏みます。

 まず、WebフォームのツールボックスからWebフォームページにGridViewコントロールをドラッグ&ドロップします。WebフォームデザイナでGridViewコントロールのインスタンスがページ上に作成されたら、GridViewを右クリックしてプロパティページを表示します。名前(ID)をgrdOrdersに変更し、AllowPagingをtrueに、AllowSortingをtrueに、AutoGenerateColumnsをfalseに、それぞれ設定します。背景色を交互に変更させたい場合は、AlternatingRowStyleプロパティを展開し、BackColorを目的の背景色に設定します。

 2つ目は、列を手動で定義する処理です。これが必要なのは、AutoGenerateColumnsプロパティをfalseに設定したためです。プロパティシートで[Columns]コレクションを選択すると、列を定義できるダイアログが表示されます(図3を参照)。このダイアログでは、バインドフィールドを追加します。それには、[BoundField]を選択して強調表示し、[Add(追加)]をクリックして、右側でDataFieldプロパティを設定します。また、ユーザーによる並べ替えを可能にする列については、SortExpressionプロパティも定義します。

図3 ASP.NET 2.0のGridViewの列の定義
図3 ASP.NET 2.0のGridViewの列の定義

 図2のGridViewの表示では、一部の列が右揃えになっています。また、2つの日付列(「Order Date」と「Ship Date」)の書式が異なっています。一方は日付のみなのに対し、もう一方は日付に加えてHH:MM形式の時刻も表示されています。

 図3で、バインドされる個々の列を追加したら、HeaderStyleおよびItemStyleの両グループプロパティのHorizontalAlignプロパティを設定できます。日付の書式はDataFormatStringプロパティで設定します。値は、日付のみの場合は{0:d}、日付と時刻(秒以外すべて)の場合は{0:g}です。なお、DataFormatStringを使用する列では、HtmlEncodeプロパティをfalseに設定する必要があります。これは、クロスサイトスクリプティングを防ぐための、ASP.NET 2.0の新しいセキュリティ機能に伴うものです。

 GridViewのデザインが済んだら、このGridViewをバインドするためのコードを記述します。

DataSet dsData = this.GetData();

// Run whatever process you want, for the query
// SELECT OrderID, CustomerID, OrderDate,
// ShippedDate, Freight FROM Orders ORDER BY
// OrderID
this.grdOrders.DataSource = dsData.Tables[0];
this.grdOrders.DataBind();

 最後に、運賃が100ドルを超える行を強調表示する機能を実装します。それには、GridViewのRowCreatedイベントを使用します。この中では、GridViewの現在の行をDataRowViewオブジェクトにキャストできます。運賃の値を判断し、背景色を設定します。

protected void grdOrders_RowCreated(object sender,
    GridViewRowEventArgs e)
{
    if (e.Row.DataItem != null)
    {
        DataRowView drv = (DataRowView)e.Row.DataItem;
        decimal nFreight = Convert.ToDecimal(drv["Freight"]);
        if (nFreight> 100)
            e.Row.BackColor = System.Drawing.Color.Yellow;
    }
}

 なお、本番環境用のコードでは、運賃のロジックはビジネス層にまとめるのが良いでしょう。また、交互表示の色は、ハードコーディングするのではなくCSSの定義を使用するとよいでしょう。

ヒント7:GridViewでの選択処理

 GridViewを使い始めて日が浅い人から、GridViewの特定の行にリンクを配置する方法を聞かれることがあります。例えば、その行の詳細情報が掲載された別のWebページを開くなどの処理を行う場合です(図4を参照)。

図4 各注文を開くリンクが設定されたASP.NET 2.0のGridView
図4 各注文を開くリンクが設定されたASP.NET 2.0のGridView

 これを実装する方法はいくつかあります。ここでは、3つの簡単な手順で済む方法を紹介します。手順1では、GridViewの列デザイナを開き、使用可能なフィールドのリストからButtonFieldを追加します(BoundFieldではありません)。ButtonTypeプロパティは「Link」のままとし、Textを「Open」など目的のテキストに設定して、CommandNameを「Select」に設定します。

 手順2は後回しにして、先に手順3を説明します。手順3では、GridViewのSelectedIndexChangedイベントを使用して、ユーザーがクリックした「Open」リンクに対応する行を判定する処理を追加します。具体的にどうすれば行を判定できるのか、疑問に思うかもしれません。GridViewにはSelectedDataKeyというデザイン時プロパティがあり、一意の識別子を設定できます。今回は、このプロパティにOrderIDを割り当てるという処理を手順2で行います。そして、手順3では、SelectedIndexChangedイベントの中でSelectedDataKeyの値を判定するというわけです。

protected void grdOrders_SelectedIndexChanged
    (object sender, EventArgs e)
{
    int nOrderID = (int) this.grdOrders.SelectedDataKey.Values
         ["OrderID"];
    // Now we can load another page with the ID
}

 この方法に関して、1つ補足しておきます。テキストリンクではなく、「開く」や「編集」を意味するアイコンを表示したい場合、基本的な手順は上記と同じですが、ButtonTypeを「Link」ではなく「Image」とし、ImageURLには、表示する画像のURLを設定します。

 ヒント6では、条件に応じて行の色を変える方法を紹介しました。場合によっては、条件に応じてGridViewにアイコンを表示するという処理が必要になるかもしれません。それを実現するには、GridViewに特別なTemplateField列を定義する必要があります。それには、WebページのHTMLソースを開き、GridViewの先頭(または末尾)の列として次のコードを追加します。

<asp:TemplateField >
    <ItemTemplate>
        <img src= '<%# GetPic(Container.DataItem) %>'/>
    </ItemTemplate>
    <ItemStyle Width="3px" />
    <HeaderStyle Width="3px" />
</asp:TemplateField>

 関数GetPicはカスタムコードです。この関数では、GridViewの現在の行をパラメータとして受け取り、使用するアイコンの画像の名前を返します。返すアイコンは、行が所定の条件を満たす場合は目的のアイコンとし、満たさない場合は空白のgifファイルにします。空文字列を返すことはできないという点に注意してください。GridViewの該当するセルに赤の×印が表示されてしまい、見苦しくなるからです。

protected string GetPic(object dataitem)
{
    string cIcon = "";
    // evaluate the row from the GridView
    bool lFlag = Convert.ToBoolean(DataBinder.Eval
        (dataitem, "ShowPictureFlag"));
    if (lFlag == true)
        cIcon = "SpecialPic.gif";
    else
        cIcon = "Blank.gif";
    return cIcon;
}

ヒント8:ASP.NET 2.0のGridViewでの並べ替え

 ヒント6で作成した基本的なGridViewでは、AllowSortingプロパティとAllowPagingプロパティをtrueに設定し、データバインドされた各列に対してSortExpressionを定義しました。このGridViewをWebブラウザで動作させると、各列見出しはリンクとして表示されます。グリッドをその列で並べ替えるときにクリックするためのリンクです。また、グリッドの下部にもリンクが表示されます(AllowPagingプロパティによるものです)。こちらは、バインドされたデータセットの全行が単一のページでは収まらない場合に、別のページに移動するためのリンクです。

 しかし悲しいかな、実際のところは、これらのリンクのどれをクリックしても、期待どおりには動いてくれず、実行時エラーのメッセージが表示されてしまいます(図5と図6を参照)。

図5 Sortingイベントの処理前のエラーメッセージ
図5 Sortingイベントの処理前のエラーメッセージ
図6 PageIndexChangingイベントの処理前のエラーメッセージ
図6 PageIndexChangingイベントの処理前のエラーメッセージ

 何がいけないかと言うと、メッセージからも分かるように、処理を正常に進めるためには、GridViewのSortingイベントとPageIndexChangingイベントにコードを追加する必要があるのです。これらのイベントはポストバックの中で発生されるので、少し前の手順に戻って、処理方法全体を見直してみる必要があります。

 SortingイベントとPageIndexChangingイベントのいずれの処理でも、基本的には、GridViewのDataSourceプロパティにアクセスして、DataSource.DefaultViewプロパティの並べ替え式を変更する必要があります。しかし、ヒント6の基本的なコードを見直してみると、アクセス可能な方法でデータソースを格納していません。従って、独自の並べ替えやページング処理のコードを実装する前に、まずはその点に対処する必要があります。

 方法の1つは、GridViewのDataSource値をViewStateにプロパティとして持たせるという方法です。次のような形です。

DataTable dtOrders
{
    get { return (DataTable)ViewState["dtOrders"]; }
    set { ViewState["dtOrders"] = value; }
}

 しかしこれでは、結果セットが巨大な場合でも、注文のリスト全体をページのViewStateに持たせることになってしまいます(これを確認するには、Webページをセットアップし、結果セットをViewStateに格納したうえで、ページを実行し、[表示]の[ソース]をクリックしてみましょう。データの量は予想よりずっと多いかもしれません)。それに、データ型によってはシリアル化できないものもあります。例えば、DataRowオブジェクトをこの方法で格納することはできません。

 別の方法としては、データのバインドを実行する時点でDataSourceをセッション変数に格納するという手もあります。再び、ヒント6のコードを基にすると、次のようになります。

DataSet dsData = this.GetData();

// Run whatever process you want, for the query
// SELECT OrderID, CustomerID, OrderDate,
// ShippedDate, Freight FROM Orders ORDER BY
// OrderID
this.grdOrders.DataSource = dsData.Tables[0];

// Store the datatable as a Session Variable
Session["dtOrders"] = dsData.Tables[0];
this.grdOrders.DataBind();

 こうして、DataSourceをセッションに格納しておけば、Sortingイベントでセッション変数にアクセスでき、データソースのDefaultViewのSortExpressionを適切に変更できます。このSortExpressionは、列に対して最初に定義したSortExpressionプロパティからのものです。

protected void grdOrders_Sorting
    (object sender, GridViewSortEventArgs e)
{
    DataTable dtOrders =
        (DataTable)Session["dtOrders"];
    if (dtOrders != null)
    {
        dtOrders.DefaultView.Sort = e.SortExpression
        this.grdOrders.DataSource = dtOrders.DefaultView;
        Session["dtOrders"] = dtOrders;
        this.grdOrders.DataBind();
    }
}

 これは、前代未聞の画期的な手法というわけではありません。ASP.NETに関するあちこちのフォーラムで、同様の手法を目にすることができます。

ヒント9:ASP.NET 2.0のGridViewでのページング

 並べ替えの問題が片づいたので、次はページングの処理に移りましょう。ユーザーがページ下部のページリンクのいずれかをクリックすると、ポストバックが生じ、PageIndexChangingイベントが発生します。ユーザーが選択したページはGridViewPageEventArgsパラメータで把握でき、その値に基づいてGridViewのPageIndexを設定します。また、それまでに行われた並べ替えを維持するために、GridViewのDataSourceのDefaultViewプロパティにアクセスする必要があります。

protected void grdOrders_PageIndexChanging
    (object sender, GridViewPageEventArgs e)
{
    // must set new PageIndex and rebind
    this.grdOrders.PageIndex = e.NewPageIndex;
    this.grdOrders.DataSource =
        ((DataTable)Session["dtOrders"]).DefaultView;
    this.grdOrders.DataBind();
}

 さて、次の話題へ進む前に、セッション変数についてひとこと。セッション変数を使うかどうかは、人によってさまざまです。愛用して頼りきりになる人もいるし、スケーラビリティの問題から異議を唱える人もいるし、その中間の人もいます。

 セッション変数を使うのは、簡単すぎるくらい簡単です。そして言うまでもなく、簡単すぎるものは、乱用される傾向が大です。『Visual Studio Magazine』誌の2003年10月号に、セッション状態の管理について、Leonard Lobel氏による素晴らしい記事が掲載されています。その中では、サーバー側で状態管理を行う7つの手法が取り上げられており、セッション情報をSQL Serverに格納する方法も紹介されています。このトピックについて理解を深めたい方には、Lobel氏の記事は大いに役立つものと思います。

次のページ
ヒント10:SQL Server 2005でのTOP N

この記事は参考になりましたか?

japan.internet.com翻訳記事連載記事一覧

もっと読む

この記事の著者

japan.internet.com(ジャパンインターネットコム)

japan.internet.com は、1999年9月にオープンした、日本初のネットビジネス専門ニュースサイト。月間2億以上のページビューを誇る米国 Jupitermedia Corporation (Nasdaq: JUPM) のニュースサイト internet.comEarthWeb.com からの最新記事を日本語に翻訳して掲載するとともに、日本独自のネットビジネス関連記事やレポートを配信。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

Kevin S. Goff(Kevin S. Goff)

.NET、Visual FoxPro、SQL Server、Crystal Reportsによる独自のWebソリューション/デスクトップソリューションを提供するコンサルティンググループ「Common Ground Solutions」の創業者兼主任コンサルタント。ソフトウェアアプリケーションの開発経...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/759 2006/12/22 09:54

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー