详解ASP.NET MVC分页的实现方法

开发 后端
这里将详细介绍ASP.NET MVC分页的实现方法,一般来说分页的实现只能靠程序员自己来设计,希望本文对大家有所帮助。

ASP.NET MVC分页已经有很多文章讲述过,这里我们将讲述的ASP.NET MVC分页的实现,需要靠自己设计,这就需要了解分页的原理,以及相关数据库的操作。51CTO编辑推荐《ASP.NET MVC框架视频教程

在ASP.NET中,GridView控件本身就带有分页的功能,只要把当前页面的索引值赋给GridView的PageIndex就可以实现了分页,至于数据怎么分页,全都由GridView封装起来了。

ASP.NET MVC分页的实现就只能靠自己来设计了。首先来说一下分页的原理。现在有一个张news表,中间有很多信息,我们假设一页显示5条记录,这样,页面数量=总记录数/5;这里,如果出现小数,得进位取整。如比总记录和数为51,那么分的页面数量是11,最后一页只有一条记录。好,有这样一个思路后,现在就来做ASP.NET MVC中的分页了。

1、 数据库和表

创建一个Data_Company的数据库,建一张news表,表结构如下图:

创建一个Data_Company的数据库

ID是主键,并助是自动增长列。

2、 现在,我们用O/R Designer来创建news表的LINQ To SQL的实体类。

创建一个名为MvcCompany的ASP.NET MVC Web Application项目,然后选中Models,右键,“添加”,“新建项”,选中C#中的“数据”,如下图:

用O/R Designer来创建news表

选择“LINQ to SQL类”,名称设为“CompanyData.dbml”,然后“添加”。

打开“服务器资源管理器”,创建连接,展开表,找到news表,拖到CompanyData.dbml的左边表视图区(注:.dbml视图左边是SQL表和SQL视图区,右边是SQL存储过程和SQL函数区),效果如下图:

服务器资源管理器

在“解决方案资源管理器”下的,“Models”多了三个文件,CompanyData.dbml,展开它,会有CompanyData.dbml.layout和CompanyData.designer.cs,前者是CompanyData.dbml视图的一些信息(比如news表在的坐标等信息),后者是news实体类及Data_Company数据库的类,在数据库类中聚合了news实体类。

3、 添加news列表类。因为一个news实体类,一次只能表示一条记录,如果呈现一个news表中的数据,最好定义一个集合类来存临时来存放news记录的集合。

类的实现如下:

  1. using System;  
  2.  using System.Collections.Generic;  
  3.  using System.Linq;  
  4.  using System.Web;  
  5.  namespace MvcCompany.Models  
  6. {  
  7. public class NewList<T> : List<T> 
  8. {  
  9. /**//// <summary> 
  10. /// 页面索引值  
  11. /// </summary> 
  12. public int PageIndex { get; private set; }  
  13. /**//// <summary> 
  14. /// 每页记录的数量  
  15. /// </summary> 
  16. public int PageSize { get; private set; }  
  17. /**//// <summary> 
  18. /// 记录总条数  
  19. /// </summary> 
  20. public int TotalCount { get; private set; }  
  21. /**//// <summary> 
  22. /// 共有的页数和  
  23. /// </summary> 
  24. public int TotalPages { get; private set; }  
  25. public NewList(IQueryable<T> source, int pageIndex, int pageSize)  
  26. {  
  27. PageIndex = pageIndex;  
  28. PageSize = pageSize;  
  29. TotalCount = source.Count();  
  30. // 进上去取整( 总记录条数/一面记录的条数)  
  31. TotalPages = (int)Math.Ceiling(TotalCount / (double)pageSize);  
  32. this.AddRange(source.Skip(pageIndex * pageSize).Take(PageSize));  
  33. }  
  34. /**//// <summary> 
  35. /// 是否存在前续页  
  36. /// </summary> 
  37. public bool HasPreviousPage  
  38. {  
  39. get { return (PageIndex > 0); }  
  40. }  
  41. /**//// <summary> 
  42. /// 是否存在后续页  
  43. /// </summary> 
  44. public bool HasNextPage  
  45. {  
  46. get { return (PageIndex + 1 < AllPages); }  
  47. }  
  48. }} 

这里,我们实现了一个泛型的集合列表NewList(当然,这里的本质上可以当其他实体类的集合列表),在这个类中间,有四个字段,访问修饰符都是public的,分另为:

PageIndex:当前页面的索引值

PageSize:每个页面的记录的条数

AllCount:记录的总条数

AllPages:共有的页面总数

在NewList 构造函数中,有如下代码:

  1. public NewList(IQueryable<T> list, int pageIndex, int pageSize)  
  2. {  
  3. PageIndex = pageIndex;   
  4.  PageSize = pageSize;  
  5. AllCount = source.Count();   
  6. AllPages = (int)Math.Ceiling(AllCount / (double)pageSize);  
  7. this.AddRange(list.Skip(PageIndex * PageSize).Take(PageSize));  

构造函的参数有三个,一个是list,就是实体类的一个集合,还有就是页面索引值和每个页面的记录条数。

第1、2代码很容易理角,第3行代码是得到列表的总记录条数,第4行代码,就完成了我们在开始时分析的分页实现的公式:页面数量=总记录数/每页记录数,其中Math.Ceiling就是把小数部分进到整数的函数。

最关键的是第5行代码,首先看Skip(PageIndex*PageSize),页面索引值乘上每页记录数,得到是当前页面以前的所有记录数,Skip是跳过这些记录,而得到后面的所有记录,Take(PageSize)是得到PageSize条数的记录,比如,我们想要第三页的记录,这个页面的索引值为2(因为索引值从0开始)PageIndex=2,每页显示5条记录,PageSize=5,就是要跳过list中的前10条记录,然后再取前5条记录,即取list中的第11条到第15条记录,也就是第3页的记录了。

在这里,微软提供了Skip和Tabke函数,让我们做起分页来,得心应手。

接下来是this.AddRange()函数,可以把批量的数据放到当前集合中(因为NewList本身就是一个集合)。

代码的后半部分是两个属性:

  1. public bool HasPreviousPage  
  2. {  
  3. get { return (PageIndex > 0); }  
  4. }  
  5. public bool HasNextPage  
  6. {  
  7. get { return (PageIndex + 1 < AllPages); }  

这两个属性是为页面显示“上一页”和“下一页”,因为当我们显示第一页的时候,“上一页”是不需要显示的,如果最后一页,是没有“下一页“的,所以在这里定义了两个属性,来判断是否有上一页和下一页。

先看HasPreviousPage属性,如果PageIndex是大于0的,说明不是在第一页,所以就反回true,如果小于等于0(在这里小于0是没有意思义的,因为页面的索引值最小是0),说明是第一页,所以返回是false。

再看HasNextPage属性,因为页面索引值的最大数,与页面的最大数差1(索引从0开始的原因),所以当PageIndex+1小于AllPages时,说没有没到最后一页,返回值是true,如果PageIndex+1大于等于AllPages时(大于也没有意义),说明是最后一页,返回值为false。

4、 添加NewsController。选中Controller,右键添加一个NewsController 的Controller。

代码如下:

  1. using System;  
  2.  using System.Collections.Generic;  
  3.  using System.Linq;  
  4.  using System.Web;  
  5. using System.Web.Mvc;  
  6. using System.Web.Mvc.Ajax;  
  7. using MvcCompany.Models;  
  8. using System.Configuration;  
  9. namespace MvcCompany.Controllers  
  10. {  
  11. public class NewsController : Controller  
  12. {  
  13. DataClassesDataContext DCDC;  
  14. int pageSize;  
  15. public NewsController()  
  16. {  
  17. DCDC = new DataClassesDataContext();  
  18. pageSize = Convert.ToInt32(ConfigurationManager.AppSettings["pagesize"]); //每个页面的数量存放在web.config的appsetting里的pagesize节中,值为5  
  19. }  
  20. public ActionResult Index(int? page)  
  21. {  
  22. var NewsList = DCDC.news.Select(newss=>newss);  
  23. var paginatedNews = new NewList<news>(NewsList, page ?? 0, pageSize); //实现分页功能  
  24. return View(paginatedNews);  
  25. }  
  26. [AcceptVerbs(HttpVerbs.Post)]  
  27. public ActionResult Index(FormCollection formValues)  
  28. {  
  29. int? index = int.Parse(formValues.GetValue("pageindex").AttemptedValue);  
  30. int page = index ??0 ;  
  31. var NewsList = DCDC.news.Select(newss => newss);  
  32. var paginatedNews = new NewList<news>(NewsList, page, pageSize); //实现分页功能  
  33. return View(paginatedNews);  
  34. }  
  35. }  
  36. }  

关于两个Index重载,我们在设计完Views再讨论。

5、 添加View。选中NewsController,右键,添加View,会弹出如下图:

添加View

在这里,我们选中MvcCompany.Models.news,在View content下拉列表中选择List(因为要实现列表分页)。

Index.aspx页面代码如下:

  1. <%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<MvcCompany.Models.NewList<MvcCompany.Models.news>>" %> 
  2. <asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server"> 
  3. 新闻  
  4. </asp:Content> 
  5. <asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server"> 
  6. <!--前半部分--> 
  7. <%using (Html.BeginForm())  
  8. { %> 
  9. <h2> 
  10. 新闻列表</h2> 
  11. <table> 
  12. <tr> 
  13. <th> 
  14. 编号  
  15. </th> 
  16. <th> 
  17. 题目  
  18. </th> 
  19. <th> 
  20. 时间  
  21. </th> 
  22. <th> 
  23. 内容  
  24. </th> 
  25. </tr> 
  26. <% foreach (var item in Model)  
  27. { %> 
  28. <tr> 
  29. <td> 
  30. <%= Html.Encode(item.ID)%> 
  31. </td> 
  32. <td> 
  33. <%= Html.Encode(item.title)%> 
  34. </td> 
  35. <td> 
  36. <%= Html.Encode(String.Format("{0:g}", item.datetimes))%> 
  37. </td> 
  38. <td> 
  39. <%= Html.Encode(item.contents)%> 
  40. </td> 
  41. </tr> 
  42. <% } %> 
  43. </table> 
  44. <hr /> 
  45. <!--后半部分--> 
  46. <% =Html.RouteLink("首页", "UpcomingNews", new { page = 0 })%>|  
  47. <% if (Model.HasPreviousPage)  
  48. {%> 
  49. <% =Html.RouteLink("上一页", "UpcomingNews", new { page = (Model.PageIndex - 1) })%>|  
  50. <%} %> 
  51. <% if (Model.HasNextPage)  
  52. {%> 
  53. <% =Html.RouteLink("下一页", "UpcomingNews", new { page = (Model.PageIndex + 1) })%>|  
  54. <%} %> 
  55. <% =Html.RouteLink("尾页", "UpcomingNews", new { page = Model.PageSize - 1 })%>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  
  56. 第  
  57. <%=Html.TextBox("pageindex", Model.PageIndex, new {style="width:30px;"})%><input 
  58. type="submit" value="转到" id="sub" /> 
  59. <%} %> 
  60. </asp:Content> 

代码的前半部分,很好理解。

代码的后半部分,我们来分析一下,首页,是采用

Html.RouteLink(“首页”,”UpcomingNews”,new{ page=0}),是要定位到名称为”UpcomingNews”的路由,这个路由在Global.asax中,代码如下:

  1. routes.MapRoute(  
  2. "UpcomingNews",  
  3. "News/page/{page}",  
  4. new { controller = "News"action = "Index" }); 

路由的名称是”UpcominNews”,Url格式是News/page/{page},News和page是url的一种格式,后面{page}是参数,这个参数的名称要与View中,后半部分的new{page=0}的page,以及NewsController中的方法Index(int? page)中的page都必需统一。如果有请求

News/page/2的url,实际上请求的是 news?page=2的页网(路由在ASP.NET MVC官上有说明)。

首页为中的page=0,最终会成为NesController中Index(int? page)方法,的实参,返回首页数据(及数据库表的前5条数据)。

上一页,在当前页数PageIndex的基础上减1。

下一页,在当前页数PageIndex的基础上加1

(注:上面的加减1都不会越界,因为当显示第一页时,“上一页”的超连接就不会显示。当最后一页时,“下一页”的超连接就不会显示)

尾页同首页。

现在的一个问题是“转到”第几页的实现,我们知道,转到第几页的“几”,得用户输入,所以这里用一个Html.TextBox来实现,完全代码是

  1. <%=Html.TextBox("pageindex", Model.PageIndex, new {style="width:30px;"})%> 

最终会生成一个名称为pageindex的intup,类型为Text,它的值始终为当前的索引页值Model.PageIndex,其中有一个宽度的属性new {style="width:30px;"}。

同时还有一个<input type="submit" value="转到" id="sub" />用来向后参提交。因为代码中有<form>表单,所以可以在NewsController中接收这个提交。

Index(FormCollection formValues)方法用来处理这个提交。这里会从formValues.GetValue("pageindex").AttemptedValue中午到客户端用户输入“pageindex”文本框中的值。从而来完成定向。

至此,我们就用ASP.NET MVC实现了一个分页功能,相比之下要难ASP.NET的GridView自动分页好多。

在这个例子中,我们在Models层中提供了实体类及news表的集合类。在Controller层增加了NewsController类。在View层增加了News的view,从M-V-C角度,分别完成了对分页的功能。

【编辑推荐】

  1. ASP.NET静态页面生成及分页的实现
  2. ASP.NET GridView分页与双向排序案例
  3. ASP.NET DataGrid自定义分页源程序
  4. ASP.NET MVC分页控件的实现
  5. DetailsView分页显示数据
责任编辑:彭凡 来源: 51CTO博客
相关推荐

2010-03-19 09:17:16

ASP.NET MVC

2009-07-28 14:47:18

ASP.NET MVC

2009-07-22 16:02:39

ASP.NET MVCPagedList

2010-01-26 13:15:42

ASP.NET MVC

2009-07-22 09:11:02

Action方法ASP.NET MVC

2009-07-20 15:44:32

ASP.NET MVC

2010-08-02 09:18:39

ASP.NET MVC

2009-10-29 09:15:32

ASP.NET MVCDropDownLis

2009-12-01 09:30:34

ASP.NET MVC

2009-09-18 10:20:26

PRG数据验证

2009-07-24 13:20:44

MVC框架ASP.NET

2009-07-31 12:43:59

ASP.NET MVC

2009-07-22 09:36:54

使用UpdataModASP.NET MVC

2009-11-06 09:23:41

ASP.NET高效分页

2011-04-14 09:19:22

ASP.NET MVC

2012-04-23 15:10:18

ASP.NET

2009-06-01 10:23:31

asp.net mvcasp.net mvc.net mvc框架

2010-02-03 09:50:58

ASP.NET MVC

2009-09-11 09:18:17

ASP.NET MVC

2010-10-12 09:52:02

ASP.NET MVC
点赞
收藏

51CTO技术栈公众号