ASP.NETカスタムコントロール9日目カスタムGridView

16029 ワード

1.引用


ASP.NET 2.0では、新しいGridViewコントロールを提供しています.これは、データGridベースの上に多くの新しい特性を追加しています.例えば、コードを1行作成しないでデータソースコントロールと組み合わせてデータの表示とページングを実現することができます.しかし、このページング効率は低く、データベースからすべてのデータを一度に読み取ってページングを行い、データ量が少なければ迅速な開発を実現することができます.しかし、データベースに大量のデータが格納されている場合、この操作性能は低いように見えます.そのため、PageIndexChangingイベントで新しいページをバインドする方法を自分で作成するのが一般的です.この場合、GridViewが1ページのデータしか読み込めない場合、共有ページ数を正しく計算できず、ページングボタンを正しく表示できないため、拡張を検討する必要があります.また、DataListコントロールは、記録内容を表示するための柔軟なテンプレート設定を提供していますが、最大の弱点は、ページングをサポートしないことです.同様に、DataListを拡張してページングの特性を増やそうとしています.

2.分析


GridViewとDataListを一緒に考えるのは、いずれのデータバインドコントロールもページングリンクリストを生成する際に同様の操作を実行する必要があるためです.GridViewコントロール自体はページングがサポートされているため、カスタムテーブルコントロールを開発する際には、適切なボタンウェアエンドコントロールを追加し、CommandNameプロパティをPageに設定し、CommandArgumentプロパティを特定の値に設定するだけで、GridViewによってページ変更イベントをキャプチャすることができ、コードに「魔法文字」が表示されないように定数クラス保存で使用される文字列定数を定義します.しかし、この方法は、クライアントの再送イベントを受信できないため、DataListクラスとGridViewクラスの違いでもある.DataListクラスはIPostBackEventHandlerインタフェースを実装していない.DataListがクライアントの再送を受信してページングイベントをトリガできるようにするには、カスタムDataListにIPostBackEventHandlerインタフェースを実装させ、カスタムイベントパラメータクラスを使用してイベントのトリガ時にページ番号情報を渡す必要がある.
カスタムGridViewとDataListコントロールでページングが可能になりました.両方のページングの外観を統一するために、ページングベースクラスを定義してページング機能を実現し、DataListページングに対してページングベースクラスを継承し、ページングボタンの再送スクリプトを設定します.最後に、改ページボタンを1つの全体として表に追加し、Table Cell(表のセル)から継承できるようにします.

3.実現


3.1コマンド文字列を保存する定数クラスConstantの作成
public class Constant

{

     public const string FIRST_PAGE = "First";

     public const string PREV_PAGE = "Prev";

     public const string NEXT_PAGE = "Next";

     public const string LAST_PAGE = "Last";

     public const string PAGE_ARGUMENT = "Page";

     public const char ARGUMENT_SPLITTER = '$';

}

ページング・ボタンのCommandArgumentプロパティは次のように設定されています.
ツールバーの
説明
First
最初のページに移動
Last
最後のページに移動
Prev
前のページに移動
Next
次のページに移動
1つの数字
特定のページに移動
3.2 DataPagerクラスを定義してページングリンクを生成する.このクラスはTable Cellクラスから継承され、プライベート変数を定義してページ番号を計算する(PagerSettingsクラスは.NET事前定義クラスであり、ページング設定に関する情報が格納されている)
public class DataPager : TableCell

{

     private int _pageIndex;

     private int _recordCount;

     private int _pageSize;

     private int _pageCount;

     private PagerSettings _settings;

}

3.3コンストラクション関数を定義し、現在のページインデックス、合計レコード数、ページサイズ情報を受信し、これらのデータから合計ページ番号を計算し、GeneratePageメソッドを呼び出してページングを生成する
public DataPager(PagerSettings setting, int pageIndex, int recordCount, int pageSize)

{

     _settings = setting;

     _pageIndex = pageIndex;

     _recordCount = recordCount;

     _pageSize = pageSize;

      _pageCount = _recordCount % _pageSize == 0 ? _recordCount / _pageSize : _recordCount / _pageSize + 1;

      GeneratePage();

}

3.3 GeneratePageメソッドを作成し、PagerSettings設定に従って数値または数値なしのページングリンクを生成する.
private void GeneratePage()

{

     if (_settings.Mode == PagerButtons.NextPrevious || _settings.Mode == PagerButtons.NextPreviousFirstLast)

     {

         GeneratePrevNextPage();

     }

     else if (_settings.Mode == PagerButtons.Numeric || _settings.Mode == PagerButtons.NumericFirstLast)

     {

         GenerateNumericPage();

     }

}

3.4二種類のページングリンクを生成する方法を作成する:
private void GeneratePrevNextPage()

{

     GeneratePage(false);

}

  private void GenerateNumericPage()

{

     GeneratePage(true);

}

3.5ページングを生成するとき、一連のLinkButtonを作成し、CommandArgumentとCommandNameのプロパティを設定するGeneratePageメソッドが呼び出されます.以下はこのメソッドの実装です.
private void GeneratePage(bool generateNumber)

{

     this.Controls.Add(new LiteralControl("  "));

      if (_recordCount > 0)

     {

         this.Controls.Add(new LiteralControl("?? "));

         this.Controls.Add(new LiteralControl(_recordCount.ToString()));

         this.Controls.Add(new LiteralControl(" ??????  ???? "));

         this.Controls.Add(new LiteralControl(_pageSize.ToString()));

         this.Controls.Add(new LiteralControl(" ??????  "));

     }

      this.Controls.Add(new LiteralControl((_pageIndex + 1).ToString()));

     this.Controls.Add(new LiteralControl("/"));

     this.Controls.Add(new LiteralControl(_pageCount.ToString()));

     this.Controls.Add(new LiteralControl("    "));

      LinkButton btnFrist = new LinkButton();

     LinkButton btnPrev = new LinkButton();

     LinkButton btnNext = new LinkButton();

     LinkButton btnLast = new LinkButton();

      if (!String.IsNullOrEmpty(_settings.FirstPageImageUrl))

     {

         btnFrist.Text = "<img src='" + ResolveUrl(_settings.FirstPageImageUrl) + "' border='0'/>";

     }

     else

     {

         btnFrist.Text = _settings.FirstPageText;

     }

     btnFrist.CommandName = Constant.PAGE_ARGUMENT;

     btnFrist.CommandArgument = Constant.FIRST_PAGE;

     btnFrist.Font.Underline = false;

      if (!String.IsNullOrEmpty(_settings.PreviousPageImageUrl))

     {

         btnPrev.Text = "<img src='" + ResolveUrl(_settings.PreviousPageImageUrl) + "' border='0'/>";

     }

     else

     {

         btnPrev.Text = _settings.PreviousPageText;

     }

     btnPrev.CommandName = Constant.PAGE_ARGUMENT;

     btnPrev.CommandArgument = Constant.PREV_PAGE;

     btnPrev.Font.Underline = false;

      if (!String.IsNullOrEmpty(_settings.NextPageImageUrl))

     {

         btnNext.Text = "<img src='" + ResolveUrl(_settings.NextPageImageUrl) + "' border='0'/>";

     }

     else

     {

         btnNext.Text = _settings.NextPageText;

     }

     btnNext.CommandName = Constant.PAGE_ARGUMENT;

     btnNext.CommandArgument = Constant.NEXT_PAGE;

     btnNext.Font.Underline = false;

      if (!String.IsNullOrEmpty(_settings.LastPageImageUrl))

     {

         btnLast.Text = "<img src='" + ResolveUrl(_settings.LastPageImageUrl) + "' border='0'/>";

     }

     else

     {

         btnLast.Text = _settings.LastPageText;

     }

     btnLast.CommandName = Constant.PAGE_ARGUMENT;

     btnLast.CommandArgument = Constant.LAST_PAGE;

     btnLast.Font.Underline = false;

      if (this._pageIndex <= 0)

     {

         btnFrist.Enabled = btnPrev.Enabled = false;

     }

     else

     {

         btnFrist.Enabled = btnPrev.Enabled = true;

     }

      this.Controls.Add(btnFrist);

     this.Controls.Add(new LiteralControl("&nbsp;&nbsp;"));

     this.Controls.Add(btnPrev);

     this.Controls.Add(new LiteralControl("&nbsp;&nbsp;"));

      if (generateNumber)

     {

         int rightCount = (int)(_settings.PageButtonCount / 2);

                  int leftCount = _settings.PageButtonCount % 2 == 0 ? rightCount - 1 : rightCount;

         for (int i = 0; i < _pageCount; i++)

         {

             if (_pageCount > _settings.PageButtonCount)

             {

                 if (i < _pageIndex - leftCount && _pageCount - 1 - i > _settings.PageButtonCount - 1)

                 {

                     continue;

                 }

                 else if (i > _pageIndex + rightCount && i > _settings.PageButtonCount - 1)

                 {

                     continue;

                 }

             }

              if (i == _pageIndex)

             {

                 this.Controls.Add(new LiteralControl("<span style='color:red;font-weight:bold'>" + (i + 1).ToString() + "</span>"));

             }

             else

             {

                 LinkButton lb = new LinkButton();

                 lb.Text = (i + 1).ToString();

                 lb.CommandName = Constant.PAGE_ARGUMENT;

                 lb.CommandArgument = (i + 1).ToString();

                  this.Controls.Add(lb);

             }

              this.Controls.Add(new LiteralControl("&nbsp;&nbsp;"));

         }

     }

      if (this._pageIndex >= _pageCount - 1)

     {

         btnNext.Enabled = btnLast.Enabled = false;

     }

     else

     {

         btnNext.Enabled = btnLast.Enabled = true;

     }

     this.Controls.Add(btnNext);

     this.Controls.Add(new LiteralControl("&nbsp;&nbsp;"));

     this.Controls.Add(btnLast);

     this.Controls.Add(new LiteralControl("&nbsp;&nbsp;"));

}

3.6カスタムGridViewクラスを作成し、このクラスはASPから継承する.NETのデフォルトGridView(System.Web.UI.WebControl.GridView):
[ToolboxData(@"<{0}:GridView runat='server'></{0}:GridView>")]

public class GridView : System.Web.UI.WebControls.GridView

{

}

3.7 GridViewプロパティを定義し、RecordCoundストレージの合計レコード数を追加し、PageIndexプロパティとPageCountプロパティを書き換えて現在のページインデックスと合計ページ数を格納します.また、MouseOverBackgroundColorプロパティを定義して、マウスをデータ行に移動したときの背景の変色を実現します.
public int RecordCount

{

     get

     {

         object o = ViewState["RecordCount"];

          return o == null ? 0 : Convert.ToInt32(o);

     }

     set

     {

         ViewState["RecordCount"] = value;

     }

}

  public override int PageIndex

{

     get

     {

         object o = ViewState["PageIndex"];

          return o == null ? 0 : Convert.ToInt32(o);

     }

     set

     {

         ViewState["PageIndex"] = value;

     }

}

  public override int PageCount

{

     get

     {

         int pageCount = RecordCount % PageSize == 0 ? RecordCount / PageSize : RecordCount / PageSize + 1;

          return pageCount;

     }

}

  public Color MouseOverBackgroundColor

{

     get

     {

         object o = ViewState["MouseOverBackgroundColor"];

         return o == null ? Color.Silver : (Color)o;

     }

     set

     {

         ViewState["MouseOverBackgroundColor"] = value;

     }

}

3.8 OnRowCreatedメソッドを書き換え、データ行の作成時にまず背景変色JavaScriptを追加し、次にページ情報に基づいてページ番号リンクセルを作成して表に追加する.
protected override void OnRowCreated(GridViewRowEventArgs e)

{

     if (e.Row.RowType == DataControlRowType.DataRow)

     {

         e.Row.Attributes.Add("onmouseover", "bgcolor=this.style.backgroundColor;this.style.backgroundColor='" + ColorTranslator.ToHtml(MouseOverBackgroundColor) + "';");

         e.Row.Attributes.Add("onmouseout", "this.style.backgroundColor=bgcolor;");

     }

      if (e.Row.RowType == DataControlRowType.Pager)

     {

         e.Row.Controls.Clear();

         TableCell tc = new DataPager(PagerSettings, PageIndex, RecordCount, PageSize);

                  tc.ColumnSpan = this.Columns.Count;

         e.Row.Controls.Add(tc);

     }

      base.OnRowCreated(e);

}

3.9最後の行のデータを削除するときに前のページにスクロールできるように、OnRowDeletedメソッドを書き換えました.
protected override void OnRowDeleting(GridViewDeleteEventArgs e)

{

     if (this.Rows.Count == 1)

         this.PageIndex = this.PageIndex - 1 >= 0 ? this.PageIndex - 1 : 0;

      base.OnRowDeleting(e);

}

3.10 WebサイトでカスタムGridViewを宣言して定義します.
<cc:GridView ID="gdvData" runat="server" PageSize="4" AllowPaging="True" OnPageIndexChanging="gdvData_PageIndexChanging" RecordCount="0" DataKeyNames="ID" Font-Size="12px" OnRowDeleting="gdvData_RowDeleting" Width="500px" AutoGenerateColumns="False" BackColor="White" BorderColor="#FFE0C0" BorderStyle="None" BorderWidth="1px" CellPadding="4" MouseOverBackgroundColor="255, 224, 192" OnRowDeleted="gdvData_RowDeleted" >

     <Columns>

         <asp:BoundField DataField="ID" HeaderText="????" />

         <asp:BoundField DataField="Name" HeaderText="????" />

         <asp:BoundField DataField="Favor" HeaderText="????" />

         <asp:CommandField ShowDeleteButton="True" HeaderText="????" />

     </Columns>

     <PagerSettings PageButtonCount="5" />

     <RowStyle BackColor="White" ForeColor="#330099" />

     <FooterStyle BackColor="#FFFFCC" ForeColor="#330099" />

     <PagerStyle BackColor="#FFFFCC" ForeColor="#330099" HorizontalAlign="Center" />

     <SelectedRowStyle BackColor="#FFCC66" Font-Bold="True" ForeColor="#663399" />

     <HeaderStyle BackColor="#990000" Font-Bold="True" ForeColor="#FFFFCC" />

     <AlternatingRowStyle BackColor="Yellow" />

</cc:GridView>

3.11データ・ソースにバインドするためのバックグラウンド・コードの作成:
protected void Page_Load(object sender, EventArgs e)

{

     if (!IsPostBack)

         this.BindData();

}

  private void BindData()

{

     UserQuery query=null;

      object o = ViewState["Query"];

      if (o == null)

         query = new UserQuery();

     else

         query = (UserQuery)o;

      int total=0;

     IList<User> users = Users.GetUsers(query, gdvData.PageIndex, gdvData.PageSize, out total);

              gdvData.RecordCount = total;

     gdvData.DataSource = users;

     gdvData.DataBind();

  }

3.12 PageIndexChangingとRowDeletingイベントハンドラを作成する:
protected void gdvData_PageIndexChanging(object sender, GridViewPageEventArgs e)

{

     gdvData.PageIndex = e.NewPageIndex;

     this.BindData(); 

}

  protected void gdvData_RowDeleting(object sender, GridViewDeleteEventArgs e)

{

     int id=Convert.ToInt32(gdvData.DataKeys[e.RowIndex].Value);

                  Users.DeleteUser(id); 

      this.BindData();

}

3.13ブラウザでページをプレビューする(このコードの中のUsersとUserクラスはすべて与えられていないので、読者は自分で書くことを試みることができて、ここでUsersクラスは1つの論理クラスに相当してユーザーの問合せと削除を実現して、Userクラスはユーザーの実体を代表する).

4.まとめ


このタスクでは、自動的にページングが可能なGridViewコントロールを作成し、ページングリンクを生成する操作を個別に抽出してDataPagerクラスを作成します.このような場合はLinkButtonを使用してCommandNameとCommandArgumentを設定してページングを実現します.次のタスクでは、このようなベースでDataListにページングプロパティを追加します.
ASP.NETカスタムコントロールシリーズ記事
前言
初日の簡単な星のコントロール
翌日はカスタムスタイルの星コントロール
3日目にコントロールのステータスを使用する星コントロール
4日目折りたたみパネルカスタムコントロール
5日目に採点できる星のコントロール
6日目にデータソースの星コントロールをバインドできます
7日目に豊富な特性を持つリストコントロールを開発
8日目に複数のエントリの星スコアを表示するデータバインドコントロール
9日目カスタムGridView
10日目にページング機能を実現するDataList
すべてのソースをダウンロード
このシリーズのPDFバージョンのダウンロード