看过 NerdDinner 那个经典MVC例子的人都知道,里面有个简单的分页例子,大致是这样的:

PaginatedList 负责对Linq的查询作skip和take得到最终的查询结果,这个结果包括记录的总数,分页的总数等等。大致结构和使用例子如下:

        public int PageIndex  { get; private set; }
        public int PageSize   { get; private set; }
        public int TotalCount { get; private set; }
        public int TotalPages { get; private set; }

        public PaginatedList(IQueryable<T> source, int pageIndex, int pageSize) {//略去...}
        public bool HasPreviousPage {
            get {
                return (PageIndex > 0);
            }
        }

        public bool HasNextPage {
            get {
                return (PageIndex+1 < TotalPages);
            }
        }

html:

 

    <div class="pagination">

        <% if (Model.HasPreviousPage) { %>
        
            <%= Html.RouteLink("<<< Previous Page", 
                               "UpcomingDinners", 
                               new { page=(Model.PageIndex-1) }) %>
        
        <% } %>
        
        <% if (Model.HasNextPage) { %>
        
            <%= Html.RouteLink("Next Page >>>", 
                               "UpcomingDinners", 
                               new { page = (Model.PageIndex + 1) })%>
        
        <% } %>    

    </div>

上面这个分页只有上一页和下一页两个选项。我曾经对它做了一下扩展,使它能显示上一页,1~N页和下一页。

其实就是在上一页和下一页之间插入以下代码:

            <% for (int i = 0; i < Model.TotalPages; i++) %>
            <%{ %>
                <%if (i != Model.PageIndex) %>
                <%{ %>
                    <%=  Html.RouteLink( (i+1).ToString (),
                                      "UpcomingDinners",
                                      new { page = i +1})%>
                <%} %>
                <%else %>
                <%{ %> 
                        <label> <%=(i+1).ToString () /*当前页*/%></label>
                <%} %>
            <%} %>
 

显示的效果是这个样子:

image

效果是基本上满足了,但是html那些臃肿的代码明显是不可能在实际应用中出现的。得帮它减减肥才行,而且打造成通用的分页代码。

我们不难发现其实只是RouteLink不同而已:Html.RouteLink( (i+1).ToString (), "UpcomingDinners", new { page = i +1})  , 大家可能都知道扩展HtmlHelper来实现是最优雅不过了。像这样的形式:

public static string Pager(this HtmlHelper html, string currentPageStr, int pageSize, int totalCount)

页面的使用例子:

<%= Html.Pager("page",Model.PageSize , Model.TotalCount )%>

啊,实在是太整洁了。上面那个“page”参数是url 的查询关键字 /Home/Index?page=1 ,或者/Home/Index/page/1, 可以改为你想要的,主要对应就OK

显示的效果:

image

下面代码是参考了重典的blog文:ASP.NET MVC雕虫小技 3、Pager

他那个版本有个小bug,而且不支持/Home/Index/page/1这种形式,我已经在其基础上修改好了。非常感谢重典提供的MVC技巧!

        /// <summary>  
        /// 分页Pager显示  
        /// </summary>   
        /// <param name="html"></param>  
        /// <param name="currentPageStr">标识当前页码的QueryStringKey</param>   
        /// <param name="pageSize">每页显示</param>  
        /// <param name="totalCount">总数据量</param>  
        /// <returns></returns> 
        public static string Pager(this HtmlHelper html, string currentPageStr, int pageSize, int totalCount)
        {
            var queryString = html.ViewContext.HttpContext.Request.QueryString;
            int currentPage = 1; //当前页  
            var totalPages = Math.Max((totalCount + pageSize - 1) / pageSize, 1); //总页数  
            var dict = new System.Web.Routing.RouteValueDictionary(html.ViewContext.RouteData.Values);
            var output = new System.Text.StringBuilder();
            if (!string.IsNullOrEmpty(queryString[currentPageStr]))
            {
                //与相应的QueryString绑定 
                foreach (string key in queryString.Keys)
                    if (queryString[key] != null && !string.IsNullOrEmpty(key))
                        dict[key] = queryString[key];
                int.TryParse(queryString[currentPageStr], out currentPage);
            }
            else
            {
                //获取 ~/Page/{page number} 的页号参数
                 int .TryParse(dict[currentPageStr].ToString(), out currentPage );
            }
            if (currentPage <= 0) currentPage = 1;
            if (totalPages > 1)
            {
                if (currentPage != 1)
                {
                    //处理首页连接  
                    dict[currentPageStr] = 1;
                    output.AppendFormat("{0} ", html.RouteLink("首页", dict));
                }
                if (currentPage > 1)
                {
                    //处理上一页的连接  
                    dict[currentPageStr] = currentPage - 1;
                    output.Append(html.RouteLink("上一页", dict));
                }
                else
                {
                    output.Append("上一页");
                }
                output.Append(" ");
                int currint = 5;
                for (int i = 0; i <= 10; i++)
                {
                    //一共最多显示10个页码,前面5个,后面5个  
                    if ((currentPage + i - currint) >= 1 && (currentPage + i - currint) <= totalPages)
                        if (currint == i)
                        {
                            //当前页处理  
                            output.Append(string.Format("[{0}]", currentPage));
                        }
                        else
                        {
                            //一般页处理 
                            dict[currentPageStr] = currentPage + i - currint;
                            output.Append(html.RouteLink((currentPage + i - currint).ToString(), dict));
                        }
                    output.Append(" ");
                }
                if (currentPage < totalPages)
                {
                    //处理下一页的链接 
                    dict[currentPageStr] = currentPage + 1;
                    output.Append(html.RouteLink("下一页", dict));
                }
                else
                {
                    output.Append("下一页");
                }
                output.Append(" ");
                if (currentPage != totalPages)
                {
                    dict[currentPageStr] = totalPages;
                    output.Append(html.RouteLink("末页", dict));
                }
                output.Append(" ");
            }
            output.AppendFormat("{0} / {1}", currentPage, totalPages);//这个统计加不加都行 
            return output.ToString();
        }

 

恩,这可能还不是最好的方案,期待更好的分页方案。

 

推荐.NET配套的通用数据层ORM框架:CYQ.Data 通用数据层框架