在ASP.NET中,GridView控件本身就帶有分頁的功能,只要把當前頁面的索引值賦給GridView的PageIndex就可以實現了分頁,至于數據怎么分頁,全都由GridView封裝起來了。
在ASP.NET MVC中分頁的實現就只能靠自己來設計了。首先來說一下分頁的原理。現在有一個張news表,中間有很多信息,我們假設一頁顯示5條記錄,這樣,頁面數量=總記錄數/5;這里,如果出現小數,得進位取整。如比總記錄和數為51,那么分的頁面數量是11,最后一頁只有一條記錄。好,有這樣一個思路后,現在就來做ASP.NET MVC中的分頁了。
1、 數據庫和表
創建一個Data_Company的數據庫,建一張news表,表結構如下圖:
ID是主鍵,并助是自動增長列。
2、 現在,我們用O/R Designer來創建news表的LINQ To SQL的實體類。
創建一個名為MvcCompany的ASP.NET MVC Web Application項目,然后選中Models,右鍵,“添加”,“新建項”,選中C#中的“數據”,如下圖:
選擇“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記錄的集合。
類的實現如下:
Code
1 using System;
2
3 using System.Collections.Generic;
4
5 using System.Linq;
6
7 using System.Web;
8
9 namespace MvcCompany.Models
10
11 {
12
13 public class NewList < T > : List < T >
14
15 {
16
17 /**/ ///
18
19 /// 頁面索引值
20
21 ///
22
23 public int PageIndex { get ; private set ; }
24
25 /**/ ///
26
27 /// 每頁記錄的數量
28
29 ///
30
31 public int PageSize { get ; private set ; }
32
33 /**/ ///
34
35 /// 記錄總條數
36
37 ///
38
39 public int TotalCount { get ; private set ; }
40
41 /**/ ///
42
43 /// 共有的頁數和
44
45 ///
46
47 public int TotalPages { get ; private set ; }
48
49 public NewList(IQueryable < T > source, int pageIndex, int pageSize)
50
51 {
52
53 PageIndex = pageIndex;
54
55 PageSize = pageSize;
56
57 TotalCount = source.Count();
58
59 // 進上去取整( 總記錄條數/一面記錄的條數)
60
61 TotalPages = ( int )Math.Ceiling(TotalCount / ( double )pageSize);
62
63 this .AddRange(source.Skip(pageIndex * pageSize).Take(PageSize));
64
65 }
66
67 /**/ ///
68
69 /// 是否存在前續頁
70
71 ///
72
73 public bool HasPreviousPage
74
75 {
76
77 get { return (PageIndex > 0 ); }
78
79 }
80
81 /**/ ///
82
83 /// 是否存在后續頁
84
85 ///
86
87 public bool HasNextPage
88
89 {
90
91 get { return (PageIndex + 1 < AllPages); }
92
93 }
94
95 }
96
97 }
98
99
這里,我們實現了一個泛型的集合列表NewList(當然,這里的本質上可以當其他實體類的集合列表),在這個類中間,有四個字段,訪問修飾符都是public的,分另為:
PageIndex:當前頁面的索引值
PageSize:每個頁面的記錄的條數
AllCount:記錄的總條數
AllPages:共有的頁面總數
在NewList 構造函數中,有如下代碼:
Code
1 public NewList(IQueryable < T > list, int pageIndex, int pageSize)
2
3 {
4
5 PageIndex = pageIndex;
6 PageSize = pageSize;
7
8 AllCount = source.Count();
9
10 AllPages = ( int )Math.Ceiling(AllCount / ( double )pageSize);
11
12 this .AddRange(list.Skip(PageIndex * PageSize).Take(PageSize));
13
14 }
15
構造函的參數有三個,一個是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本身就是一個集合)。
代碼的后半部分是兩個屬性:
public bool HasPreviousPage
{
get { return (PageIndex > 0); }
}
public bool HasNextPage
{
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。
代碼如下:
Code
1 using System;
2
3 using System.Collections.Generic;
4
5 using System.Linq;
6
7 using System.Web;
8
9 using System.Web.Mvc;
10
11 using System.Web.Mvc.Ajax;
12
13 using MvcCompany.Models;
14
15 using System.Configuration;
16
17 namespace MvcCompany.Controllers
18
19 {
20
21 public class NewsController : Controller
22
23 {
24
25 DataClassesDataContext DCDC;
26
27 int pageSize;
28
29 public NewsController()
30
31 {
32
33 DCDC = new DataClassesDataContext();
34
35 pageSize = Convert.ToInt32(ConfigurationManager.AppSettings[ " pagesize " ]); // 每個頁面的數量存放在web.config的appsetting里的pagesize節中,值為5
36
37 }
38
39 public ActionResult Index( int ? page)
40
41 {
42
43 var NewsList = DCDC.news.Select(newss => newss);
44
45 var paginatedNews = new NewList < news > (NewsList, page ?? 0 , pageSize); // 實現分頁功能
46
47 return View(paginatedNews);
48
49 }
50
51 [AcceptVerbs(HttpVerbs.Post)]
52
53 public ActionResult Index(FormCollection formValues)
54
55 {
56
57 int ? index = int .Parse(formValues.GetValue( " pageindex " ).AttemptedValue);
58
59 int page = index ?? 0 ;
60
61 var NewsList = DCDC.news.Select(newss => newss);
62
63 var paginatedNews = new NewList < news > (NewsList, page, pageSize); // 實現分頁功能
64
65 return View(paginatedNews);
66
67 }
68
69 }
70
71 }
72
73
關于兩個Index重載,我們在設計完Views再討論。
5、 添加View。選中NewsController,右鍵,添加View,會彈出如下圖:
在這里,我們選中MvcCompany.Models.news,在View content下拉列表中選擇List(因為要實現列表分頁)。
Index.aspx頁面代碼如下:
Code
1
2
3 < asp:Content ID ="Content1" ContentPlaceHolderID ="TitleContent" runat ="server" >
4
5 新聞
6
7 asp:Content >
8
9 < asp:Content ID ="Content2" ContentPlaceHolderID ="MainContent" runat ="server" >
10
11
12
13
16
17 < h2 >
18
19 新聞列表h2 >
20
21 < table >
22
23 < tr >
24
25 < th >
26
27 編號
28
29 th >
30
31 < th >
32
33 題目
34
35 th >
36
37 < th >
38
39 時間
40
41 th >
42
43 < th >
44
45 內容
46
47 th >
48
49 tr >
50
51
54
55 < tr >
56
57 < td >
58
59
60
61 td >
62
63 < td >
64
65
66
67 td >
68
69 < td >
70
71
72
73 td >
74
75 < td >
76
77
78
79 td >
80
81 tr >
82
83
84
85 table >
86
87 < hr />
88
89
90
91 |
92
93
96
97 |
98
99
100
101
104
105 |
106
107
108
109
110
111 第
112
113 頁 < input
114
115 type ="submit" value ="轉到" id ="sub" />
116
117
118
119 asp:Content >
120
121
代碼的前半部分,很好理解。
代碼的后半部分,我們來分析一下,首頁,是采用
Html.RouteLink(“首頁”,”UpcomingNews”,new{ page=0}),是要定位到名稱為”UpcomingNews”的路由,這個路由在Global.asax中,代碼如下:
routes.MapRoute(
"UpcomingNews",
"News/page/{page}",
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來實現,完全代碼是
最終會生成一個名稱為pageindex的intup,類型為Text,它的值始終為當前的索引頁值Model.PageIndex,其中有一個寬度的屬性new {style="width:30px;"}。
同時還有一個 用來向后參提交。因為代碼中有