.Net MVC4 使用心得(三)實現分頁控制元件
之前寫的,很凌亂,而且,幾乎不粘程式碼,這不便於理解和也無法直接尋找可用程式碼。以後的文章會盡量引入程式碼例項。
這次需要一個翻頁控制元件。之前webform直接拖個aspnetpager,寫寫前臺樣式和後臺程式碼就好了,需要資料繫結時可以直接用pager控制元件的屬性,或者可以直接在sqldatasource或者entitydatasource裡繫結parameter為controlparameter,指向相應控制元件的屬性。(程式碼就不找了)
現在MVC框架下,服務端控制元件被取消了,似乎分頁變得複雜了不少。尋找微軟提供的解決方案,沒有找到。(可能是我找的不夠細緻)在網上看到說自己寫個HtmlHelper的擴充套件,小研究了一下,發現不是很符合我的胃口。哈哈,那就自己整吧。
先看下擴充套件:
必須由要擴充套件的型別同一名稱空間的下的類承載,一般定義為static class,命名為擴充套件功能+Extensions。對於類中的方法,應當使用static方法。方法的第一個引數為要擴充套件的型別,並使用this修飾符。 還有就是,擴充套件方法作為靜態方法,無法訪問被擴充套件物件的非靜態方法和屬性。
好了,開工。擴充套件參考了網上某位同仁的程式碼,但是程式碼基本上重寫了,保留了思想,哈哈。忘記地址了,這裡就不貼了。
using System.Reflection; using System.Text; using System.Web.Routing; namespace System.Web.Mvc { #region 分頁配置類 /// <summary> /// 分頁元素位置 /// </summary> public enum PagerElementPosition { Left, Right } /// <summary> /// 配合Pager擴充套件,分頁控制元件設定類 /// </summary> public class PagerConfig { /// <summary> /// 記錄總條數 /// </summary> public int TotalRecord { get; set; } /// <summary> /// 記錄的單位,預設為“條” /// </summary> public string RecordUnit { get; set; } /// <summary> /// 記錄的名稱,預設為“記錄” /// </summary> public string RecordName { get; set; } /// <summary> /// 當前頁碼的引數名 /// </summary> public string CurrentPageKey { get; set; } /// <summary> /// 當前頁碼 只讀 /// </summary> public int CurrentPage { get { if (HttpContext.Current.Request.Params[CurrentPageKey] == null) { return 1; } else { try { int currentPage = Convert.ToInt32(HttpContext.Current.Request.Params[CurrentPageKey]); if (currentPage < 1) { return 1; } else if (currentPage > TotalPage) { return TotalPage; } else { return currentPage; } } catch { return 1; } } } } private int _PageSize; /// <summary> /// 每頁顯示記錄數 /// </summary> public int PageSize { get { return _PageSize; } set { if (value < 1) { _PageSize = 1; } else { _PageSize = value; } } } /// <summary> /// 總頁數 只讀 /// </summary> public int TotalPage { get { return (int)Math.Ceiling(TotalRecord / (double)PageSize); } } /// <summary> /// 是否顯示首頁、尾頁連結 /// </summary> public bool ShowFirstLastPageLink { get; set; } /// <summary> /// 是否顯示上一頁、下一頁連結 /// </summary> public bool ShowPrevNextPageLink { get; set; } /// <summary> /// 是否顯示數字按鈕 /// </summary> public bool ShowDigitalLink { get; set; } /// <summary> /// 數字按鈕數量 /// </summary> public int DigitalLinkCount { get; set; } /// <summary> /// 是否顯示總記錄數 /// </summary> public bool ShowTotalRecord { get; set; } /// <summary> /// 總記錄數出現位置 /// </summary> public PagerElementPosition TotalRecordPosition { get; set; } /// <summary> /// 是否顯示當前頁數和總頁數資訊 /// </summary> public bool ShowPageInfo { get; set; } /// <summary> /// 當前頁和總頁數資訊顯示位置 /// </summary> public PagerElementPosition PageInfoPosition { get; set; } /// <summary> /// 是否顯示GoTo輸入區域 /// </summary> public bool ShowGoTo { get; set; } /// <summary> /// 指定生成的元素對應的class的字首字元 /// </summary> public string CssClassPreWord { get; set; } /// <summary> /// 是否建立為ajax分頁控制元件 /// </summary> public bool UseAjax { get; set; } /// <summary> /// Ajax提交後更新的html元素id /// </summary> public string AjaxUpdateTargetID { get; set; } /// <summary> /// Ajax提交後呼叫的js function名稱 /// </summary> public string AjaxSuccessFunctionName { get; set; } /// <summary> /// 是否自動生成Ajax提交後呼叫的js function /// </summary> public bool AutoGenarateAjaxSuccessFunction { get; set; } /// <summary> /// 使用預設值初始化設定 /// </summary> public PagerConfig() { PageSize = 20; RecordUnit = "條"; RecordName = "記錄"; CurrentPageKey = "page"; CssClassPreWord = "pager"; ShowFirstLastPageLink = true; ShowPrevNextPageLink = true; ShowDigitalLink = true; DigitalLinkCount = 10; ShowTotalRecord = false; TotalRecordPosition = PagerElementPosition.Left; ShowPageInfo = false; PageInfoPosition = PagerElementPosition.Left; ShowGoTo = false; UseAjax = false; AjaxUpdateTargetID = ""; AjaxSuccessFunctionName = "OnPageChanged"; AutoGenarateAjaxSuccessFunction = true; } } #endregion /// <summary> /// 配合Pager擴充套件實現分頁的幫助類 /// </summary> public class PagerHelper { /// <summary> /// 獲取記錄開始和結束編號,並返回實際的頁碼 /// </summary> /// <param name="allCount">記錄總條數</param> /// <param name="pageSize">頁大小</param> /// <param name="pageIndex">(輸出)當前頁碼</param> /// <param name="startIndex">(輸出)開始編號</param> /// <param name="endIndex">(輸出)結束編號</param> /// <param name="currentPageKey">分頁引數名稱</param> /// <param name="pageIndexIs0Based">頁碼編號是否從0開始,預設為否</param> /// <param name="recordIndexIs0Based">記錄編號是否從0開始,預設為否</param> public static void GetStartAndEndIndex(int allCount, int pageSize, out int pageIndex, out int startIndex, out int endIndex, string currentPageKey = "page", bool pageIndexIs0Based = false, bool recordIndexIs0Based = false) { //計算pageIndex的實際值 pageIndex = GetRealPageIndex(allCount, pageSize, currentPageKey, pageIndexIs0Based); //計算過程是0based的 if (!pageIndexIs0Based) { pageIndex--; //轉成0based } //計算startIndex和endIndex startIndex = pageIndex * pageSize; endIndex = startIndex + pageSize - 1; if (endIndex > allCount - 1) { endIndex = allCount - 1; } //0based計算完成,下面根據設定不同,輸出不同 if (!pageIndexIs0Based) { pageIndex++; } if (!recordIndexIs0Based) { startIndex++; endIndex++; } } /// <summary> /// 返回實際頁碼 /// </summary> /// <param name="allCount">總記錄數</param> /// <param name="pageSize">頁面大小</param> /// <param name="currentPageKey">分頁引數名稱</param> /// <param name="pageIndexIs0Based">頁碼編號是否從0開始,預設為否</param> /// <returns>實際頁碼</returns> public static int GetRealPageIndex(int allCount, int pageSize, string currentPageKey = "page", bool pageIndexIs0Based = false) { int pageIndex; //整個計算過程都是0based的 if (pageSize < 1) { pageSize = 1; //容錯 } if (HttpContext.Current.Request.Params[currentPageKey] == null) { pageIndex = 0; } else { try { int _pageIndex = Convert.ToInt32(HttpContext.Current.Request.Params[currentPageKey]); //待判斷的頁碼 if (!pageIndexIs0Based) { _pageIndex--; //轉成0based } if (_pageIndex < 0) { pageIndex = 0; } else { int totalPage = (int)Math.Ceiling(allCount / (double)pageSize); if (_pageIndex >= totalPage) { pageIndex = totalPage - 1; } else { pageIndex = _pageIndex; } } } catch { pageIndex = 0; } } //0based計算完成,下面根據設定不同,輸出不同 return (pageIndexIs0Based) ? pageIndex : pageIndex + 1; } } } namespace System.Web.Mvc.Html { public static class PagerExtensions { //提取 返回a標籤 方法 private static string getLinkHtml(UrlHelper urlHelper, bool useAjax, string ajaxSuccessFunction, string linkContent, string actionName, string controllerName, RouteValueDictionary routeValues) { string link = ""; if (useAjax) { link += "<a href=\"javascript:$.post('" + urlHelper.Action(actionName, controllerName) + "',{"; //將route放到post表單中 foreach (var route in routeValues.Keys) { link += route + ":'" + routeValues[route].ToString() + "',"; } if (routeValues.Count > 0) { link = link.Remove(link.Length - 1); } link += "}," + ajaxSuccessFunction + ")\" >"; } else { link += "<a href=\"" + urlHelper.Action(actionName, controllerName, routeValues) + "\">"; } link += linkContent; link += "</a>"; return link; } #region 分頁擴充套件 /// <summary> /// 返回用於分頁的div元素 /// </summary> /// <param name="htmlHelper">HtmlHelper</param> /// <param name="pagerConfig">分頁設定物件</param> /// <returns></returns> public static MvcHtmlString Pager(this HtmlHelper htmlHelper, PagerConfig pagerConfig) { return Pager(htmlHelper, "", "", new { }, new { }, pagerConfig); } /// <summary> /// 返回用於分頁的div元素 /// </summary> /// <param name="htmlHelper">HtmlHelper</param> /// <param name="htmlAttributes">html屬性物件</param> /// <param name="pagerConfig">分頁設定物件</param> /// <returns></returns> public static MvcHtmlString Pager(this HtmlHelper htmlHelper, object htmlAttributes, PagerConfig pagerConfig) { return Pager(htmlHelper, "", "", new { }, htmlAttributes, pagerConfig); } /// <summary> /// 返回用於分頁的div元素 /// </summary> /// <param name="htmlHelper">HtmlHelper</param> /// <param name="actionName">方法</param> /// <param name="htmlAttributes">html屬性物件</param> /// <param name="pagerConfig">分頁設定物件</param> /// <returns></returns> public static MvcHtmlString Pager(this HtmlHelper htmlHelper, string actionName, object htmlAttributes, PagerConfig pagerConfig) { return Pager(htmlHelper, actionName, "", new { }, htmlAttributes, pagerConfig); } /// <summary> /// 返回用於分頁的div元素 /// </summary> /// <param name="htmlHelper">HtmlHelper</param> /// <param name="actionName">方法</param> /// <param name="controllerName">控制器</param> /// <param name="htmlAttributes">html屬性物件</param> /// <param name="pagerConfig">分頁設定物件</param> /// <returns></returns> public static MvcHtmlString Pager(this HtmlHelper htmlHelper, string actionName, string controllerName, object htmlAttributes, PagerConfig pagerConfig) { return Pager(htmlHelper, actionName, controllerName, new { }, htmlAttributes, pagerConfig); } /// <summary> /// 返回用於分頁的div元素 /// </summary> /// <param name="htmlHelper">HtmlHelper</param> /// <param name="actionName">方法</param> /// <param name="controllerName">控制器</param> /// <param name="routeValues">路由引數</param> /// <param name="htmlAttributes">html屬性物件</param> /// <param name="pagerConfig">分頁設定物件</param> /// <returns></returns> public static MvcHtmlString Pager(this HtmlHelper htmlHelper, string actionName, string controllerName, object routeValues, object htmlAttributes, PagerConfig pagerConfig) { RouteValueDictionary RouteValues; if (routeValues == null) { RouteValues = new RouteValueDictionary(); } else { RouteValues = new RouteValueDictionary(routeValues); } UrlHelper Url = new UrlHelper(htmlHelper.ViewContext.RequestContext); AjaxHelper Ajax = new AjaxHelper(htmlHelper.ViewContext, htmlHelper.ViewDataContainer); StringBuilder sbPager = new StringBuilder(); sbPager.Append("<div"); //利用反射獲取htmlAttributes的全部元素和值 if (htmlAttributes != null) { PropertyInfo[] htmlProperties = htmlAttributes.GetType().GetProperties(); foreach (var property in htmlProperties) { sbPager.Append(" " + property.Name + "=\"" + property.GetValue(htmlAttributes).ToString() + "\""); } } sbPager.Append(">"); //左側記錄總數資訊 if (pagerConfig.ShowTotalRecord && pagerConfig.PageInfoPosition == PagerElementPosition.Left) { sbPager.Append("<span class=\"" + pagerConfig.CssClassPreWord + "-count\">共" + pagerConfig.TotalRecord + pagerConfig.RecordUnit + pagerConfig.RecordName + "</span>"); } //左側頁碼資訊 if (pagerConfig.ShowPageInfo && pagerConfig.PageInfoPosition == PagerElementPosition.Left) { sbPager.Append("<span class=\"" + pagerConfig.CssClassPreWord + "-info\">第" + pagerConfig.CurrentPage + "頁/共" + pagerConfig.TotalPage + "頁</span>"); } //首頁 if (pagerConfig.ShowFirstLastPageLink) { if (pagerConfig.CurrentPage > 1) { RouteValues[pagerConfig.CurrentPageKey] = 1; sbPager.Append("<span class=\"" + pagerConfig.CssClassPreWord + "-btn\">" + getLinkHtml(Url, pagerConfig.UseAjax, pagerConfig.AjaxSuccessFunctionName, "首頁", actionName, controllerName, RouteValues) + "</span>"); } else { sbPager.Append("<span class=\"" + pagerConfig.CssClassPreWord + "-btn\">首頁</span>"); } } //上一頁 if (pagerConfig.ShowPrevNextPageLink) { if (pagerConfig.CurrentPage > 1) { RouteValues[pagerConfig.CurrentPageKey] = pagerConfig.CurrentPage - 1; sbPager.Append("<span class=\"" + pagerConfig.CssClassPreWord + "-btn\">" + getLinkHtml(Url, pagerConfig.UseAjax, pagerConfig.AjaxSuccessFunctionName, "上一頁", actionName, controllerName, RouteValues) + "</span>"); } else { sbPager.Append("<span class=\"" + pagerConfig.CssClassPreWord + "-btn\">上一頁</span>"); } } //數字導航開始 if (pagerConfig.ShowDigitalLink) { int shownStartPageIndex, shownEndPageIndex; //總頁數少於要顯示的頁數,頁碼全部顯示 if (pagerConfig.DigitalLinkCount >= pagerConfig.TotalPage) { shownStartPageIndex = 1; shownEndPageIndex = pagerConfig.TotalPage; } else//顯示指定數量的頁碼 { int forward = (int)Math.Ceiling(pagerConfig.DigitalLinkCount / 2.0); if (pagerConfig.CurrentPage > forward)//起始頁碼大於1 { shownEndPageIndex = pagerConfig.CurrentPage + pagerConfig.DigitalLinkCount - forward; if (shownEndPageIndex > pagerConfig.TotalPage)//結束頁碼大於總頁碼結束頁碼為最後一頁 { shownStartPageIndex = pagerConfig.TotalPage - pagerConfig.DigitalLinkCount + 1; shownEndPageIndex = pagerConfig.TotalPage; } else { shownStartPageIndex = pagerConfig.CurrentPage - forward + 1; } } else//起始頁碼從1開始 { shownStartPageIndex = 1; shownEndPageIndex = pagerConfig.DigitalLinkCount; } } //向上… if (shownStartPageIndex > 1) { RouteValues[pagerConfig.CurrentPageKey] = shownStartPageIndex - 1; sbPager.Append("<span class=\"" + pagerConfig.CssClassPreWord + "-number\">" + getLinkHtml(Url, pagerConfig.UseAjax, pagerConfig.AjaxSuccessFunctionName, "...", actionName, controllerName, RouteValues) + "</span>"); } //數字 for (int i = shownStartPageIndex; i <= shownEndPageIndex; i++) { if (i != pagerConfig.CurrentPage) { RouteValues[pagerConfig.CurrentPageKey] = i; sbPager.Append("<span class=\"" + pagerConfig.CssClassPreWord + "-number\">" + getLinkHtml(Url, pagerConfig.UseAjax, pagerConfig.AjaxSuccessFunctionName, i.ToString(), actionName, controllerName, RouteValues) + "</span>"); } else { sbPager.Append("<span class=\"" + pagerConfig.CssClassPreWord + "-number " + pagerConfig.CssClassPreWord + "-currentnum\">" + i.ToString() + "</span>"); } } //向下… if (shownEndPageIndex < pagerConfig.TotalPage) { RouteValues[pagerConfig.CurrentPageKey] = shownEndPageIndex + 1; sbPager.Append("<span class=\"" + pagerConfig.CssClassPreWord + "-number\">" + getLinkHtml(Url, pagerConfig.UseAjax, pagerConfig.AjaxSuccessFunctionName, "...", actionName, controllerName, RouteValues) + "</span>"); } } ////數字導航結束 //下一頁 if (pagerConfig.ShowPrevNextPageLink) { if (pagerConfig.CurrentPage < pagerConfig.TotalPage) { RouteValues[pagerConfig.CurrentPageKey] = pagerConfig.CurrentPage + 1; sbPager.Append("<span class=\"" + pagerConfig.CssClassPreWord + "-btn\">" + getLinkHtml(Url, pagerConfig.UseAjax, pagerConfig.AjaxSuccessFunctionName, "下一頁", actionName, controllerName, RouteValues) + "</span>"); } else { sbPager.Append("<span class=\"" + pagerConfig.CssClassPreWord + "-btn\">下一頁</span>"); } } //尾頁 if (pagerConfig.ShowFirstLastPageLink) { if (pagerConfig.CurrentPage < pagerConfig.TotalPage) { RouteValues[pagerConfig.CurrentPageKey] = pagerConfig.TotalPage; sbPager.Append("<span class=\"" + pagerConfig.CssClassPreWord + "-btn\">" + getLinkHtml(Url, pagerConfig.UseAjax, pagerConfig.AjaxSuccessFunctionName, "尾頁", actionName, controllerName, RouteValues) + "</span>"); } else { sbPager.Append("<span class=\"" + pagerConfig.CssClassPreWord + "-btn\">尾頁</span>"); } } //右側記錄總數資訊 if (pagerConfig.ShowTotalRecord && pagerConfig.PageInfoPosition == PagerElementPosition.Right) { sbPager.Append("<span class=\"" + pagerConfig.CssClassPreWord + "-count\">共" + pagerConfig.TotalRecord + pagerConfig.RecordUnit + pagerConfig.RecordName + "</span>"); } //右側頁碼資訊 if (pagerConfig.ShowPageInfo && pagerConfig.PageInfoPosition == PagerElementPosition.Right) { sbPager.Append("<span class=\"" + pagerConfig.CssClassPreWord + "-info\">第" + pagerConfig.CurrentPage + "頁/共" + pagerConfig.TotalPage + "頁</span>"); } //頁碼輸入框 if (pagerConfig.ShowGoTo) { RouteValues[pagerConfig.CurrentPageKey] = "--pageRouteValue--"; sbPager.Append("<span class=\"" + pagerConfig.CssClassPreWord + "-goto\">轉到第<input class=\"" + pagerConfig.CssClassPreWord + "-goto-input\" type=\"text\" url=\"" + Url.Action(actionName, controllerName, RouteValues) + "\" />頁"); if (pagerConfig.UseAjax) { sbPager.Append("<input class=\"" + pagerConfig.CssClassPreWord + "-goto-submit\" type=\"button\" value=\"GO\" onclick=\"$.post( $(this).prev().attr('url').replace('--pageRouteValue--',$(this).prev().val())," + pagerConfig.AjaxSuccessFunctionName + ")\" /></span>"); } else { sbPager.Append("<input class=\"" + pagerConfig.CssClassPreWord + "-goto-submit\" type=\"button\" value=\"GO\" onclick=\"window.location = $(this).prev().attr('url').replace('--pageRouteValue--',$(this).prev().val());\" /></span>"); } } //ajax分頁回撥函式 if (pagerConfig.UseAjax) { if (pagerConfig.AutoGenarateAjaxSuccessFunction) { sbPager.Append("<script type=\"text/javascript\">function " + pagerConfig.AjaxSuccessFunctionName + "(data){$('#" + pagerConfig.AjaxUpdateTargetID + "').html(data);}</script>"); } } sbPager.Append("</div>"); return MvcHtmlString.Create(sbPager.ToString()); } #endregion } }
之前只實現了url分頁,後來根據需要,又增加了ajax分頁,ajax分頁要配合一個返回partialview的action來使用,具體就是調整調整useajax為true,調整AjaxUpdateTargetID,如果需要在一個頁面中多次使用分頁控制元件,可能還需要用到AjaxSuccessFunctionName和AutoGenarateAjaxSuccessFunction。幾個分頁控制元件如果使用相同的處理方法,只需要一個設定AutoGenarateAjaxSuccessFunction為true即可,其餘為false,如果分別用不同的處理方法,則設定每個PagerConfig的AjaxSuccessFunctionName屬性。
呼叫方法:
在controller利用PagerHelper實現分頁:
int pageSize = 20;
int allCount = db.WebVideoCom_User.Count();
ViewBag.Num = allCount;
ViewBag.PageSize = pageSize;
int pageIndex, startIndex, endIndex;
//獲取開始和結束的記錄序號
PagerHelper.GetStartAndEndIndex(allCount, pageSize, out pageIndex, out startIndex, out endIndex);
//呼叫儲存過程返回指定序號範圍的資料
return View(db.SelectUserList(startIndex, endIndex));
view:
@Html.Pager(new PagerConfig { TotalRecord = ViewBag.Num, PageSize = ViewBag.PageSize })
然後只需要寫寫css就好了,關鍵是使用起來方便,這是我著手重寫的主要原因這樣,終於把view解放了