在开发项目中,写了一个分页实现的例子,现在把源代码贴上,以供以后写代码时参考
在列表的头部,有如下显示,
这个代表一个页面显示10条记录,总共22条记录。
这个是页面底部的显示
那么如何来显示这个分页效果,如何来写一个泛型的通用的分页类实现分页效果呢
第1个类 Paging.cs
这个类包括分页需要的一些变量,包括 页面数PageCount, 上面图片中Previous,Next是否显示, 以及Previous 和 Next对应的链接URL, 以及组成URL的各部分
using System; using System.Collection.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Web; public class Paging { public string PrependStr = string.Empty; public string UrlPart; public string NextHrefUrl = ""; public string PrevHrefUrl = ""; public bool IsPreviousVisible = false; public bool IsNextVisible = false; private int _pageCount; private string _summary; public int[] Numbers {get; set;} public int PageSize {get; set;} public int PageNo { get { int pageNo = 1; if(HttpContext.Current.Request["page"] != null && !String.IsNullOrEmpty(HttpContext.Current.Request["page"])) { Int32.TryParse(HttpContext.Current.Request["page"], out pageNo); } return pageNo; } } public void BindPaging(string urlPart, int recordCount, int pageSize, string prependStr, string summary) { _pageCount = (int)Math.Ceiling((decimal)recordCount / pageSize); UrlPart = urlPart.Split('?')[0]; _summary = summary; PrependStr = prependStr; Numbers = new int[_pageCount]; for(int i = 1; i <= _pageCount; i++) Numbers[i-1] = i; PrepagePaging(); } protected void PreparePaging() { if(PageNo == 1) IsPreviousVisible = false; if (PageNo == 1 && _pageCount == 1) { IsPreviousVisible = false; IsNextVisible = false; } else if (PageNo == 1 && PageNo < _pageCount) { IsPreviousVisible = false; IsNextVisible = true; NextHrefUrl = UrlPart + "?page=" + (PageNo + 1).ToString() + PrependStr; } else if (PageNo > 1 && PageNo < _pageCount) { IsPreviousVisible = true; PrevHrefUrl = UrlPart + "?page=" + (PageNo - 1).ToString() + PrependStr; IsNextVisible = true; NextHrefUrl = UrlPart + "?page=" + (PageNo + 1).ToString() + PrependStr; } else if (PageNo == _pageCount) { IsPreviousVisible = true; PrevHrefUrl = UrlPart + "?page=" + (PageNo - 1).ToString() + PrependStr; IsNextVisible = false; } } }
上面这个类是分页需要的类,我们当然还需要一个类,来实现分页中的实际页面,也就是PagedResult, 但是因为我们并不知道页面中的具体内容,我们是要做一个通用的例子,所以,使用泛型来实现
第2个类 PagedResult.cs
我们来看看这个类, 我们先定义一个泛型接口 IPagedResult<T>
public interface IPagedResult<T> { ICollection<T> Result {get;} int Total {get;} int CurrentPage {get; set;} int PageCount {get; set;} int PageSize {get; set;} int RowCount {get; set;} bool IsEmpty {get;} void Add(T entity); string GetCurrentPageRangeString(); }
接下来我们再定义一个泛型类PagedResult<T>,来继承这个泛型接口
public class PagedResult<T> : IPagedResult<T> { private readonly Collection<T> _result; private readonly int _total; //依赖注入 构造函数 public PagedResult(IEnumerable<T> result, int total) { _result = new Collection<T>(new List<T>(result)); // 这里也是一个小知识点,可以通过new List(IEnumerable) 把IEnumerable类型转为List类型 _total = total; } public PagedResult() : this(new List<T>(),0) { } public int CurrentPage {get; set;} public bool IsEmpty { get { return _result.Count == 0; } } public int PageCount {get; set;} public int PageSize {get; set;} public ICollection<T> Result { get { return _result; } } public int RowCount {get; set;} public int Total { get { return _total; } } public void Add(T entity) { _result.Add(entity); } public string GetCurrentPageRangeText() { CurrentPage = CurrentPage == 0 ? 1: CurrentPage; var start = PageSize * (CurrentPage - 1) + 1; var end = CurrentPage * PageSize <= Total ? start + PageSize -1 : Total; if(Total == 0) return "No results found"; string resultsOf = "results of"; string showing = "Showing"; return string.Format("{0} {1} - {2} {3} {4}", showing, start, end, resultsOf, Total); } }
我们还需要一个类,是根据类的结果列表来获取它的页结果列表PagedResult, 这是一个帮助类. 我们给它取名为PaginationHelper.cs
public static class PaginationHelper { public static int TotalPage(int total, int rowPerPage) { if((total == 0) || (rowPerPage == 0)) { return 1; } if((total % rowPerPage) == 0) { return total / rowPerPage; } double result = Convert.ToDouble(total / rowPerPage); result = Math.Ceiling(result); return Convert.ToInt32(result) + 1; } public static int StartIndex(int? page, int rowPerPage) { return (page.HasValue && (page.Value > 1)) ? ((page.Value -1) * rowPerPage) : 0; } public static PagedResult<T> GetPagedResultSet<T>(IEnumerable<T> resultSet, int pageSize, int? currentPage) { if(resultSet == null) return new PagedResult<T>(); var result = new List<T>(resultSet); //这个是把IEnumerable转换为List的方法 var resultCount = result.Count; var startIndex = StartIndex(currentPage, pageSize); var results = result.Skip(startIndex).Take(pageSize); // 这里放的是当前这个页面的结果列表,因为我们在View中需要列出当前那页的结果列表 var pageTotals = TotalPage(resultCount,pageSize); if(currentPage.HasValue && currentPage > pageTotals) currentPage = null; var pageResultSet = new PagedResult<T>(results,resultCount) { CurrentPage = currentPage.HasValue ? currentPage.Value : 1, PageCount = pageTotals, PageSize = pageSize }; return pagedResultSet; } public static PagedResult<T> GetPagedResult<T>(Func<IEnumerable<T>> func, int pageSize, int? currentPageIndex) where T : class { return GetPagedResultSet(func(), pageSize, currentPageIndex); }
现在我们开始写这个View
写这个图显示的View, 它用的Model 就是上面的Paging.cs, 我们可以看到,这个类Paging.cs没有关注分页的内容是什么,也就是它拥有完全的通用性,无论分页中的内容具体是什么,都可以使用这个来实现这个图示例的分页,那我们现在来看看这个View是怎么写的
Paging.cshtml
@inherits UmbracoViewPage<Paging> @if (Model.Numbers.Length > 1) { <div class="row"> <div class="col-md-6"> <div class="pagination-page"> <ul> @if (Model.IsPreviousVisible) { <li> <a href="@Model.PrevHref">Previous</a> </li> } @foreach (var number in Model.Numbers) { var urlHref = Model.UrlPart + "?page=" + (number).ToString() + Model.PrependStr; <li class="@(number == Model.PageNo ? "active" : string.Empty)"> <a href="@urlHref">@number</a> </li> } @if (Model.IsNextVisible) { <li> <a href="@Model.NextHref">Next</a> </li> } </ul> </div> </div> </div> }
这里面还有一些css 我就不贴在这里了,CSS及格式可以自己设置调整
接下来我们就来看看分页内容的实现,也就是说每一页中的内容的实现
我们举个例子,这个列表是News的列表,每页显示10条News,每一条News上的title上是一个链接,点击这个链接会打开一个新的页面(有这个news的URL去链接到另一个页面)来显示这个news的全部内容
显示每页News内容的页面,所使用的Model是NewsSearchResult, 具体如下
NewsSearchResult.cs
public class NewsSearchResult { public NewsSearchResult() { } public int? PageNo {get; set;} public IPagedResult<NewsResult> NewsResults {get; set;} public Paging Paging {get; set;} }
可以看到,它这里用到了我们上面定义的Paging类,已经接口IPagedResult<T>, 里面又有一个类NewsResult, 定义的是每一个News所包含的一些基本属性(title, url等), 我们来看看它的定义
NewsResult.cs
public class NewsResult { public string NewsTitle {get; set;} public string NewsDesc {get; set;} public string NewsDate {get; set;} public string PageUrl {get; set;} }
定义好了model后,我们来看看MVC中的Controller的实现,我们取名为SearchController.cs
SearchController.cs
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; public class SearchController : Controller { public ActionResult Render() { return View("NewsListSearch.cshtml", BuildInitialModel()); } public NewsSearchResult BuildInitialModel() { NewsSearchResult model = new NewsSearchResult(); model.PageNo = !string.IsNullOrEmpty(Request["page"]) ? Int32.Parse(Request["page"]) : 0; List<NewsResult> newsResults = GetAllNewsList(); Paging paging = new Paging(); IPagedResult<NewsResult> pagedResultSet = null; pagedResultSet = PaginationHelper.GetPagedResultSet(newsResults,10,paging.PageNo); //每页面显示10条结果 paging.BindPaging(Request.RawUrl, pagedResultSet.Total,10,string.Empty,string.Empty); model.Paging = paging; model.NewsResults = pagedResultSet; return model; } private List<NewsResult> GetAllNewsList() { List<NewsResult> allNewsResults = new List<NewsResult>{ new NewsResult {NewsTitle = "News 1", NewsDesc = "This is the description for News 1", NewsDate = "2017-01", PageUrl = "www.ournews.com/list/news1"}, new NewsResult {NewsTitle = "News 2", NewsDesc = "This is the description for News 2", NewsDate = "2017-02", PageUrl = "www.ournews.com/list/news2"}, new NewsResult {NewsTitle = "News 3", NewsDesc = "This is the description for News 3", NewsDate = "2017-03", PageUrl = "www.ournews.com/list/news3"}, new NewsResult {NewsTitle = "News 4", NewsDesc = "This is the description for News 4", NewsDate = "2017-04", PageUrl = "www.ournews.com/list/news4"}, new NewsResult {NewsTitle = "News 5", NewsDesc = "This is the description for News 5", NewsDate = "2017-05", PageUrl = "www.ournews.com/list/news5"}, new NewsResult {NewsTitle = "News 6", NewsDesc = "This is the description for News 6", NewsDate = "2017-06", PageUrl = "www.ournews.com/list/news6"}, new NewsResult {NewsTitle = "News 7", NewsDesc = "This is the description for News 7", NewsDate = "2017-07", PageUrl = "www.ournews.com/list/news7"}, new NewsResult {NewsTitle = "News 8", NewsDesc = "This is the description for News 8", NewsDate = "2017-08", PageUrl = "www.ournews.com/list/news8"}, new NewsResult {NewsTitle = "News 9", NewsDesc = "This is the description for News 9", NewsDate = "2017-09", PageUrl = "www.ournews.com/list/news9"}, new NewsResult {NewsTitle = "News 10", NewsDesc = "This is the description for News 10", NewsDate = "2017-10", PageUrl = "www.ournews.com/list/news10"}, new NewsResult {NewsTitle = "News 11", NewsDesc = "This is the description for News 11", NewsDate = "2017-11", PageUrl = "www.ournews.com/list/news11"}, new NewsResult {NewsTitle = "News 12", NewsDesc = "This is the description for News 12", NewsDate = "2017-12", PageUrl = "www.ournews.com/list/news12"}, new NewsResult {NewsTitle = "News 13", NewsDesc = "This is the description for News 13", NewsDate = "2018-01", PageUrl = "www.ournews.com/list/news13"}, new NewsResult {NewsTitle = "News 14", NewsDesc = "This is the description for News 14", NewsDate = "2018-02", PageUrl = "www.ournews.com/list/news14"}, new NewsResult {NewsTitle = "News 15", NewsDesc = "This is the description for News 15", NewsDate = "2018-03", PageUrl = "www.ournews.com/list/news15"}, new NewsResult {NewsTitle = "News 16", NewsDesc = "This is the description for News 16", NewsDate = "2018-04", PageUrl = "www.ournews.com/list/news16"}, new NewsResult {NewsTitle = "News 17", NewsDesc = "This is the description for News 17", NewsDate = "2018-05", PageUrl = "www.ournews.com/list/news17"}, new NewsResult {NewsTitle = "News 18", NewsDesc = "This is the description for News 18", NewsDate = "2018-06", PageUrl = "www.ournews.com/list/news18"}, new NewsResult {NewsTitle = "News 19", NewsDesc = "This is the description for News 19", NewsDate = "2018-07", PageUrl = "www.ournews.com/list/news19"}, new NewsResult {NewsTitle = "News 20", NewsDesc = "This is the description for News 20", NewsDate = "2018-08", PageUrl = "www.ournews.com/list/news20"}, new NewsResult {NewsTitle = "News 21", NewsDesc = "This is the description for News 21", NewsDate = "2018-09", PageUrl = "www.ournews.com/list/news21"}, new NewsResult {NewsTitle = "News 22", NewsDesc = "This is the description for News 22", NewsDate = "2018-10", PageUrl = "www.ournews.com/list/news22"}, new NewsResult {NewsTitle = "News 23", NewsDesc = "This is the description for News 23", NewsDate = "2018-11", PageUrl = "www.ournews.com/list/news23"}, new NewsResult {NewsTitle = "News 24", NewsDesc = "This is the description for News 24", NewsDate = "2018-12", PageUrl = "www.ournews.com/list/news24"} } } }
现在我们来看看这个展示结果页面的View, 也就是每一个页面实际显示的View ===> NewsList.cshtml
@inherits UmbracoViewPage<NewsSearchResult> <div class="col-md-12"> <div class="support-item" style="padding-bottom:0px"> @foreach (var newsResult in Model.NewsResults.Result) { <a href="@newsResult.PageUrl">@newsResult.NewsTitle</a> <div> <p class="small">@newsResult.NewsDesc</p> <a href="@newsResult.PageUrl"> <span class="small">Read News ›</span> </a> </div> </div> </div> } </div> </div>
这上面的 Model.NewsResults.Result 里面是当前页面的那个10条News结果
最后,我们来看看页面顶部的 显示当前News记录顺序的View, 就是显示如下图示的View
我们给这个View取名为ShowingDesc.cshtml, 内容如下
@inherits UmbracoViewPage<NewsSearchResult> <div class="col-md-6"> @if (Model.NewsResults.Total > 0) { <p class="pagination-result" style="text-align: left;"> <strong> @Model.NewsResults.GetCurrentPageRangeString() </strong> </p> } </div>
到目前为止,页面的3部分都有了,分别是 ShowingDesc.cshtml, NewsList.cshtml,Paging.cshtml 我们把它们组成最后的显示页面 NewsListSearch.cshtml
@inherits Umbraco.Web.Mvc.UmbracoViewPage<NewsSearchResult> <div class="col-md-12"> @Html.Partial("ShowingDesc.cshtml", Model) <hr /> </div> @Html.Partial("NewsList.cshtml", Model) <div class="col-md-12"> @Html.Partial("Paging.cshtml", Model.Paging) </div>