ASP.NET MVCでページャの表示
ページング表示(とグリッド表示)の例がMVCContribにも入っていますが、ページャの見せ方はアプリケーション固有のものなので、MVCContribを参考にしてカスタムページャを作ってみるテスト(・∀・)
とりあえず対象とするデータ構造は以下の様な感じで。
// ページング用モデルのインタフェース public interface IPagination { // 現在ページ int Page { get; } // ページ数 int MaxPage { get; } // 前ページあり? bool HasPreviousPage { get; } // 次ページあり? bool HasNextPage { get; } }
実装の例としては、次の様な感じで。
// シンプルなページング用モデルの実装 public class Pagination<T> : IEnumerable<T>, IPagination { private readonly IEnumerable<T> dataSource; public int Page { get; private set; } public int MaxPage { get; private set; } public bool HasPreviousPage { get { return Page > 1; } } public bool HasNextPage { get { return Page < MaxPage; } } public Pagination(IEnumerable<T> dataSource, int page, int maxPage) { this.dataSource = dataSource; Page = page; MaxPage = maxPage; } public IEnumerator<T> GetEnumerator() { return this.dataSource.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } }
Controllerでは一覧の検索と件数の取得を行い、それからPagination
っで、次がページャUI用の拡張メソッド。
public static class AppHelper { // 拡張メソッド public static Pager Pager(this HtmlHelper htmlHelper, IPagination pagination) { return new Pager( pagination, htmlHelper.ViewContext.HttpContext.Request ); } }
htmlの構築自体は次のPagerクラスのToString()で行うので、ここではPagerのインスタンスを作って、htmlの構築に必要なIPaginationとHttpRequestBaseを渡すだけ。
// ページャUI構築クラス public class Pager { private readonly IPagination pagination; private readonly HttpRequestBase request; private string prevString = "<前"; private string nextString = "次>"; private string pagerCss = "pager"; private string currentCss = "current"; private string disableCss = "disable"; private string parameterName = "page"; private int showLinks = 10; // コンストラクタ public Pager(IPagination pagination, HttpRequestBase request) { this.pagination = pagination; this.request = request; } // Fluentなカンジで設定するためのメソッド類 public Pager ParameterName(string parameterName) { this.parameterName = parameterName; return this; } ... public Pager ShowLinks(int showLinks) { this.showLinks = showLinks; return this; } // タグ構築ベタ書き(´д`;) public override string ToString() { StringBuilder builder = new StringBuilder(); // 描画範囲 int start; int end; if( this.pagination.MaxPage > this.showLinks ) { start = this.pagination.Page - ( this.showLinks / 2 ); end = this.pagination.Page + ( this.showLinks / 2 ); if( start < 1 ) { start = 1; } else if( end > this.pagination.MaxPage ) { start = this.pagination.MaxPage - this.showLinks + 1; } end = start + this.showLinks - 1; } else { start = 1; end = this.pagination.MaxPage; } // 開始 builder.Append( String.Format( "<div class=\"{0}\">\n", this.pagerCss ) ); // 先頭 if( this.pagination.Page > 1 ) { builder.Append( CreatePageLink( this.pagination.Page - 1, this.prevString ) ); builder.Append( " " ); } else { builder.Append( String.Format( "<span class=\"{0}\">{1}</span> ", this.disableCss, this.prevString ) ); } // ... if( this.pagination.HasPreviousPage ) { builder.Append( "... " ); } // ページ for( int i = start; i <= end; i++ ) { if( i != start ) { builder.Append( " " ); } if( i == this.pagination.Page ) { builder.Append( String.Format( "<span class=\"{0}\">{1}</span>", this.currentCss, i ) ); } else { builder.Append( CreatePageLink( i, i.ToString() ) ); } } // ... if( end < this.pagination.MaxPage ) { builder.Append( " ..." ); } // 最後 if( this.pagination.HasNextPage ) { builder.Append( " " ); builder.Append( CreatePageLink( this.pagination.Page + 1, this.nextString ) ); } else { builder.Append( String.Format( " <span class=\"{0}\">{1}</span>", this.disableCss, this.nextString ) ); } // 終了 builder.Append( "\n</div>\n" ); return builder.ToString(); } // リンク作成 private string CreatePageLink(int page, string text) { string queryString = CreateQueryString( this.request.QueryString ); return string.Format( "<a href=\"{0}?{1}={2}{3}\">{4}</a>", this.request.FilePath, this.parameterName, page, queryString, text ); } // クエリ文字列作成 private string CreateQueryString(NameValueCollection values) { StringBuilder builder = new StringBuilder(); foreach( string key in values.Keys ) { if( key == this.parameterName ) { continue; } foreach( var value in values.GetValues( key ) ) { builder.AppendFormat( "&{0}={1}", key, value ); } } return builder.ToString(); } }
先頭と最後へのナビゲーションは省略して、それっぽいHTMLが出力されるような処理を書いてみました(´Д`)
っで、使い方はこげな風(・ω・)
<%= Html.Pager( Model ) %>
パラメータを指定したい場合はこげな風(・ω・)
<%= Html.Pager( Model ).ParameterName( "p" ).ShowLinks( 20 ) %>
ちなにみ出力されるのはこんなカンジのHTML。
<div class="pager"> <span class="disable"><前</span> <span class="current">1</span> <a href="/Hoge?page=2">2</a> <a href="/Hoge?page=3">3</a> <a href="/Hoge?page=2">次></a> </div>
StringBuilderでの構築なら、JavaのタグライブラリやPHP用に作ってたヘルパーなんかから、処理自体はほぼそのまま持ってくることができますね。
タグクラウドとか、レーティングとか(・∀・)
まあ、使わないんだけど。