在這篇MVC學習(四)幾種分頁的實現(2)博文中,根據URL中傳入的兩個參數(頁碼數,首頁、上一頁、下一頁、末頁的標記符)來得到對應的分頁數據,html
只是傳入的參數太多,調用起來不太方便(標記符不可以寫錯,須要添加新的路由),所以,若是URL只傳入頁碼數就太好,順着這個思路,有了第三種分頁方式。數據庫
實現分頁形式以下圖所示。服務器
下面說說個人思路吧。asp.net
爲了在試圖文件中呈現<input type="text" ...> ,咱們須要寫上代碼@Html.TextBox(Asp.net MVC 3語法),爲了呈現Lable,須要寫@Html.Label,ide
這裏的@Html,有一個管理它的類 HtmlHelper。爲了使用方便,我決定對HtmlHelper類進行擴展。post
考慮到有些頁面不須要「上一頁」,「下一頁」之間的「100001」,所以,決定由兩種呈現形式,一個是普通的分頁,一個是帶數字的分頁,只有兩種分頁模式,新建一個枚舉類型PageMode,代碼以下學習
/// <summary> /// 分頁模式 /// </summary> public enum PageMode { /// <summary> /// 普通分頁模式 /// </summary> Normal, /// <summary> /// 普通分頁加數字分頁 /// </summary> Numeric }
面向對象,對象老是很重要的,所以,頁面對象是首先須要抽象出來的。ui
我但願展示的形式是 「總共XX條記錄,共XX頁,當前第X頁 首頁 1 2... 上一頁 下一頁 末頁」,想一想這段話中,「記錄數量」,「共多少頁」,「第幾頁」,還有一條隱形「每頁展現數據的大小」,所以,抽象出頁面對象PagerInfo(TotalPageCount能夠放入這個類中),代碼以下。this
public class PagerInfo { public int RecordCount { get; set; } public int CurrentPageIndex { get; set; } public int PageSize { get; set; } }
第一步,如何擴展HtmlHelper。url
首先,給你們看看微軟如何@Html.Label的代碼,看下面的截圖
在研究了這段代碼後,就能夠寫一個普通的HtmlHelper擴展了,代碼以下
public static MvcHtmlString Pager(this HtmlHelper helper, string id, int currentPageIndex, int pageSize, int recordCount, object htmlAttributes, string className, PageMode mode) { TagBuilder builder = new TagBuilder("table"); builder.IdAttributeDotReplacement = "_"; builder.GenerateId(id); builder.AddCssClass(className); builder.MergeAttributes(new RouteValueDictionary(htmlAttributes)); return builder.ToMvcHtmlString(TagRenderMode.Normal); }
"string id"表示這個控件的id號,「int currentPageIndex」表示須要顯示第幾頁數據的頁碼,
「int pageSize"表示每頁顯示數據的大小,」object htmlAttributes「表示屬性, 」string className「表示樣式屬性。
看了個人HtmlHepler擴展代碼,在與微軟的原始代碼比較之後,會發現我少了一行重要的代碼,就是」tagBuilder.SetInnerText(str);「,即控件在View
的呈現形式。不管是asp.net WebForm頁面的服務器控件,仍是相似"<input type="text" runat="server">」控件,或者是asp.net MVC的@Html.Label,
他們在頁面的都是以字符串的形式展示。
有了這個思路,寫出普通的分頁形式就比較簡單了。
咱們只須要給TagBuilder給予正確的字符串就好了。
一、首先得到總的記錄數,總頁數
總記錄數 int pageCount =Convert.ToInt32(Math.Ceiling((double)RecordCount / (double)PageSize));//得到總頁數
二、普通分頁如何實現
假設咱們的url形式爲 「http://localhost:11507/Home/FY3?page=2」,那麼下一頁的url形式即是「http://localhost:11507/Home/FY3?page=3」,所以,咱們須要獲得傳來的絕對路徑,不含任何參數。而後根據傳來的當前頁碼數,判斷是否有下一頁,上一頁,而且獲得格式化後的url。
這裏我先理一理頁碼數如何傳入HtmlHelper中的。
首先,Controller從URL中獲取CurrentPageIndex,而後放入PageInfo對象,而且得到分頁數據(InfoSource);
而後,咱們將InfoSource與PageInfo兩個對象放入一個泛型容器PagerQuery<T>,返回給View;
最後,HtmlHelper根據View頁面中的對象得到所需參數。
如今回到HtmlHelper的擴展實現。
得到咱們須要ULR格式化字符串,以下代碼。
var url=new StringBuilder();
url.Append(HttpContext.Current.Request.Url.AbsolutePath+"?page={0}");
我但願展示的形式是 「總共XX條記錄,共XX頁,當前第X頁 首頁 上一頁 下一頁 末頁」。如今開始拼字符串。
var sb=new StringBuilder();
sb.Append("<tr><td>");
sb.AppendFormat("總共{0}條記錄,共{1}頁,當前第{2}頁 ",RecordCount,pageCount,currentPageIndex);
//RecordCount,currentPageIndex 值經過PagerInfo傳遞過來
if(currentPageIndex==1{
sb.Append("<span>首頁</span> ";) //若是第一頁 不須要給首頁真實的連接
}
else{
var url1=string.Format(url.ToString(),1); //格式化URL 獲得第一頁的url 「http://localhost:11507/Home/FY3?page=1」
sb.AppendFormat("<span><a href={0} 首頁</a></span> ",url1);
}
如何類推,可獲得上一頁、下一頁、末頁的連接。
那麼,若是上一頁與下一頁須要顯示數字,怎麼辦呢? 這裏,默認顯示10個數字(若是頁數不夠,就按實際頁數顯示)
private static string GetNumericPage(int currentPageIndex, int pageSize, int recordCount, int pageCount, string url) { var k = currentPageIndex / 10; var m = currentPageIndex % 10; var sb = new StringBuilder(); if (currentPageIndex / 10 == pageCount / 10)//10個號碼 爲一組 { if (m == 0) { k--; m = 10; } else m = pageCount % 10; } else m = 10; for (var i = k * 10 + 1; i <= k * 10 + m; i++)//若是是第1頁 則 1...10 第11頁,則11...20 //for(int i=currentPageIndex;i<LastPage;i++) { if (i == currentPageIndex) sb.AppendFormat("<span><font color=red><b>{0}</b></font></span> ", i); else { var url1 = string.Format(url, i); sb.AppendFormat("<span><a href={0}>{1}</a></span> ", url1, i); } } return sb.ToString(); } }
如今,能夠獲得擴展標籤代碼,以下
public static MvcHtmlString Pager(this HtmlHelper helper, string id, int currentPageIndex, int pageSize, int recordCount, object htmlAttributes, string className, PageMode mode) { TagBuilder builder = new TagBuilder("table"); builder.IdAttributeDotReplacement = "_"; builder.GenerateId(id); builder.AddCssClass(className); builder.MergeAttributes(new RouteValueDictionary(htmlAttributes)); builder.InnerHtml = GetNormalPage(currentPageIndex, pageSize, recordCount, mode); return builder.ToMvcHtmlString(TagRenderMode.Normal); } static MvcHtmlString ToMvcHtmlString(this TagBuilder tagBuilder, TagRenderMode renderMode) { return new MvcHtmlString(tagBuilder.ToString(renderMode)); }
獲得分頁字符串代碼了,以下
private static string GetNormalPage(int currentPageIndex, int PageSize, int RecordCount, PageMode mode) { int pageCount =Convert.ToInt32(Math.Ceiling((double)RecordCount / (double)PageSize));//得到總頁數 var url = new StringBuilder(); url.Append(HttpContext.Current.Request.Url.AbsolutePath + "?page={0}"); var sb = new StringBuilder(); sb.Append("<tr><td>"); sb.AppendFormat("總共{0}條記錄,共{1}頁,當前第{2}頁 ", RecordCount, pageCount, currentPageIndex); if (currentPageIndex == 1) sb.Append("<span>首頁</span> "); else { var url1 = string.Format(url.ToString(), 1); sb.AppendFormat("<span><a href={0}>首頁</a></span> ", url1); } if (currentPageIndex > 1) { var url1 = string.Format(url.ToString(), currentPageIndex - 1); sb.AppendFormat("<span><a href={0}>上一頁</a></span> ", url1); } else sb.Append("<span>上一頁</span> "); if (mode == PageMode.Numeric) sb.Append(GetNumericPage(currentPageIndex, PageSize, RecordCount, pageCount, url.ToString())); if (currentPageIndex < pageCount) { string url1 = string.Format(url.ToString(), currentPageIndex + 1); sb.AppendFormat("<span><a href={0}>下一頁</a></span> ", url1); } else sb.Append("<span>下一頁</span> "); if (currentPageIndex == pageCount) sb.Append("<span>末頁</span> "); else { string url1 = string.Format(url.ToString(), pageCount); sb.AppendFormat("<span><a href={0}>末頁</a></span> ", url1); } return sb.ToString(); }
那麼,承載數據的容器時什麼呢,由於Model是會隨時變化的(泛型類最佳實現),代碼以下
public class PagerQuery<T> : List<T> { public PagerQuery(PagerInfo pager, IEnumerable<T> source) { this.Pager = pager; int BeforePageIndex = pager.CurrentPageIndex - 1; if (BeforePageIndex < 0) { BeforePageIndex = 1; } var entityList = source.Skip((BeforePageIndex) * pager.PageSize).Take(pager.PageSize); AddRange(entityList); } public PagerInfo Pager { get; set; } }
Controller代碼以下
public ActionResult FY2(int? page) { LZSEntities _lzsDb=new LZSEntities(); PagerInfo pager = new PagerInfo(); pager.RecordCount = _lzsDb.MyTestPages.Count(); pager.PageSize = 5; if (page == null) { pager.CurrentPageIndex = 1; } else { pager.CurrentPageIndex = Convert.ToInt32(page); } var result = _lzsDb.MyTestPages; IEnumerable<MyTestPages> info2 = result; var query = new PagerQuery<MyTestPages>(pager, info2); return View(query); }
View代碼以下
@model MVCFY2.PageHelpers.PagerQuery<MVCFY2.Models.MyTestPages> @using MVCFY2.Models @using MVCFY2.PageHelpers; @{ Layout = null; } <!DOCTYPE html> <html> <head> <title>FY3</title> </head> <body> @* ReSharper disable once Html.Obsolete *@ <table cellpadding="0" cellspacing="0" height="200px" width="300px" bordercolor="blue"> <tr> <th height="30px"> 序號 </th> </tr> @foreach (var item in Model) { <tr> <td align="center" height="30px"> @item.Id </td> </tr> } </table> <div> <p> @Html.Pager("pager1", Model.Pager.CurrentPageIndex, Model.Pager.PageSize, Model.Pager.RecordCount, PageMode.Numeric)</p> </div> </body> </html>
VS 2010 MVC3,配置好數據庫後,運行便可,源代碼點此下載。
我感受,第三種分頁形式是很完美的,只是重複從第一頁跳到最後一頁再最後一頁跳至第一頁,分頁緩慢,查看資源管理器,內存被佔了不少,不曾釋放,所以,
但願各位能夠告訴我高效的改進方法~~~