1. 程式人生 > >.Net MVC4 使用心得(三)實現分頁控制元件

.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解放了