.NET TIPS

[ASP.NET]DataGridコントロールでビューステートを使用せずにページ表示するには?

デジタルアドバンテージ
2003/10/10

 DataGridコントロールは、ほかのASP.NETのコントロールと同様に、ビューステートを用いてポストバック時に状態を自動復元することが可能だ。ところがDataGridコントロールでビューステートを使用した場合、HTMLに埋め込まれてサーバから送信される状態復元のためのデータはほかのコントロールと比べてかなり多く、通信回線によってはクライアントのレスポンスが悪くなることがある。このため、ビューステートを無効に設定しておき、ポストバック時には毎回プログラムでデータ連結を行うことにより、アクセス時の転送量を減らすようにしている場合が少なくない。

 しかし、DataGridコントロールでページング機能を使用した一覧表示を行う場合には「TIPS:[ASP.NET]DataGridコントロールでページ表示するには?」でも記述しているように、標準的なコーディングではビューステートを有効にしておかなければ正しくページ移動を行うことができない(デフォルトはビューステートが有効)。ここでは、ビューステートを使用せずにDataGridコントロールでページングを行う方法を示す。

 なお、本稿では「TIPS:[ASP.NET]DataGridコントロールでページ表示するには?」で示したページングを行うDataGridコントロールのサンプル・プログラム(pagingdg.aspx)をベースにして、ビューステートを無効にしても正しくページ移動処理がなされるようなプログラムを作成していく。

ビューステートを無効にした場合の現象

 まずDataGridコントロールでビューステートを無効にする方法だが、これはEnableViewState="false"属性を<asp:DataGrid>タグに追加すればよい。

  <asp:DataGrid id="MyGrid"
      AllowPaging="true"
      PageSize="5"
      OnPageIndexChanged="MyGrid_Paging"
      AutoGenerateColumns="false"
      EnableViewState="false"
      runat="server">
    ……
  </asp:DataGrid>

 この設定だけを行ってページにアクセスしても、取りあえず最初のページは正しく表示され、またHTMLソースを表示させるとEnableViewState属性を指定しなかった場合に比べてビューステート(name="__VIEWSTATE"属性の付いた<input>要素)の量がぐっと減っているのが分かるだろう。

ビューステートを無効にして表示したグリッドの最初のページ

 しかし、ここで次ページに移動するために「>」をクリックすると、グリッドはまったく表示されなくなる。MyGrid_Pagingメソッドに、次のようなデバッグのためのメッセージ表示文を追加すれば、ページ移動時に呼び出されるはずのこのメソッドが呼び出されていないことが分かるだろう。

void MyGrid_Paging(object sender, DataGridPageChangedEventArgs e) {
  Response.Write((e.NewPageIndex + 1) + "ページ目に移動します");
  MyGrid.CurrentPageIndex = e.NewPageIndex;
  BindMyGrid();
}

 ビューステートを無効にすると、このメソッドが呼び出されるトリガーとなるPageIndexChangedイベントが発生しなくなるのだろうか? 正確にはこれは正しくない。なぜなら初回のアクセス時にしかデータ連結を行わないようにしている次のPage_Loadメソッドを、

void Page_Load(object s, EventArgs e) {
  if (!IsPostBack) {
    BindMyGrid();
  }
}

ポストバック時も含めて常にデータ連結するように、次のように書き換えればビューステートが無効でも2ページ目が正しく表示されるからだ。

void Page_Load(object s, EventArgs e) {
  BindMyGrid();
}

 ビューステートが有効な場合、その復元処理によりデータ連結後の状態のDataGridコントロールが再現されるわけだが、上記の処理はPage_Loadメソッドでそのような状態を作り出していると考えればよいだろう。つまり、データ連結されたDataGridコントロールが存在する場合にPageIndexChangedイベントが発生すると考えることができる。

現在ページのインデックスの保持

 上記の変更で、ビューステートを無効にしても2ページ目へは正しく移動できるようになった。しかし3ページ目に移動しようとすると「2ページ目に移動します」という先ほどMyGrid_Pagingメソッドで追加したデバッグ・メッセージが表示され、グリッドのデータは2ページ目のままとなる。

 結論からいうと、2ページ目で「>」をクリックした場合、3ページ目に移動するのではなく、「現在のページ+1」ページ目に移動するような作りになっていることが原因のようだ(これはデータソースの要素数を10ページ分以上に増やし、ページャのモードを「NumericPages」にしてページ番号表示にし、11ページ目以降に移動してみればよく分かる)。本来、現在のページのインデックス(DataGridコントロールのCurrentPageIndexプロパティ)はビューステートにより保持されるものである。よって、ビューステートを無効にしたままページングを行うには、少なくとも現在のページが何ページ目かを独自に管理しなくてはならない。

 セッションをまたがってデータを保持する方法はASP.NETにはいくつか用意されているが、ここではページ(Pageオブジェクト)のViewStateプロパティを使用して現在ページのインデックスを保持することにしよう。このViewStateプロパティを利用して、現在ページのインデックスを読み書きするための次のようなプロパティをまず定義しておく。

int MyCurrentPageIndex {
  get { return (int)ViewState["CurrentPage"]; }
  set { ViewState["CurrentPage"] = value; }
}

 さて、現在のページが変化するタイミングはただ1つ、ページ移動が指示されたときである。よって、MyGrid_Pagingメソッドで移動先のページを(次にポストバックされたときの)現在ページとして保存しておく。

void MyGrid_Paging(object sender, DataGridPageChangedEventArgs e) {
  MyCurrentPageIndex = e.NewPageIndex;
  MyGrid.CurrentPageIndex = e.NewPageIndex;
  BindMyGrid();
}

 こうして保存しておいたページのインデックスは、Page_Loadメソッドでデータ連結を行う際に設定する(ページ移動時には常にPage_Loadメソッドの後にMyGrid_Pagingメソッドが順に呼び出されることに注意)。

void Page_Load(object s, EventArgs e) {
  if (!IsPostBack) {
    MyCurrentPageIndex = 0;
  }
  MyGrid.CurrentPageIndex = MyCurrentPageIndex;
  BindMyGrid();
}

 これで必要な処理は揃った。

ビューステートを使用しないでページングを行うサンプル・プログラム

 以上の変更を「TIPS:[ASP.NET]DataGridコントロールでページ表示するには?」で示したサンプル・プログラム(pagingdg.aspx)に加えたプログラム・コードは次のようになる。ポイントとなる個所は太字で示した。

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

<html>
<head>
  <script runat="server">
    void BindMyGrid() {
      DataSet ds = new DataSet();
      ds.ReadXml("http://www.buildinsider.net/rss");

      MyGrid.DataSource = ds.Tables["item"];
      MyGrid.DataBind();
    }

    int MyCurrentPageIndex {
      get { return (int)ViewState["CurrentPage"]; }
      set { ViewState["CurrentPage"] = value; }
    }


    void Page_Load(object s, EventArgs e) {
      if (!IsPostBack) {
        MyCurrentPageIndex = 0;
      }
      MyGrid.CurrentPageIndex = MyCurrentPageIndex;
      BindMyGrid();

    }

    void MyGrid_Paging(object sender, DataGridPageChangedEventArgs e) {
      MyCurrentPageIndex = e.NewPageIndex;
      MyGrid.CurrentPageIndex = e.NewPageIndex;
      BindMyGrid();
    }
  </script>
</head>

<body>
  <form runat="server">
    <asp:DataGrid id="MyGrid"
        AllowPaging="true"
        PageSize="5"
        OnPageIndexChanged="MyGrid_Paging"
        AutoGenerateColumns="false"
        EnableViewState="false"
        runat="server">

      <HeaderStyle BackColor="#BB2255" ForeColor="white"/>
      <ItemStyle   BackColor="#FFEEEE" />
      <AlternatingItemStyle BackColor="#FFDDDD" />

      <Columns>
        <asp:TemplateColumn HeaderText="No">
          <ItemTemplate>
            <%# Container.DataSetIndex + 1 %>
          </ItemTemplate>
        </asp:TemplateColumn>
        <asp:BoundColumn
          DataField="title" HeaderText="タイトル" />
        <asp:BoundColumn
          DataField="encoded" HeaderText="概要" />
      </Columns>

    </asp:DataGrid>

  </form>
</body>
</html>
ビューステートを使用しないでページングを行うC#のサンプル・プログラム(novspager.aspx)

 このサンプル・プログラムはここ(www.iwebmethod.netのページ)から実行して試すことができる。End of Article

カテゴリ:Webフォーム 処理対象:DataGridコントロール
使用ライブラリ:DataGridコントロール
関連TIPS:[ASP.NET]DataGridコントロールでページ表示するには?
 
この記事と関連性の高い別の.NET TIPS
[ASP.NET]DataGridコントロールでページ表示するには?
[ASP.NET]ビューステートに保存されるものは?
[ASP.NET]DataGridコントロールで大量のデータをページ表示するには?
[ASP.NET]ポストとポストバックの違いは?
[ASP.NET]DataGridコントロールのページ移動ボタンをカスタマイズするには?
このリストは、(株)デジタルアドバンテージが開発した
自動関連記事探索システム Jigsaw(ジグソー) により自動抽出したものです。
generated by

「.NET TIPS」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間