一、前言:
GridView中的分页是用post做的,所以将查询表单中的内容可以存到ViewState中,翻页的时候可以利用,实现起来就比较容易些,而在mvc中这些就要我们自己来做了,Contrib中的分页只能应付简单应用,对于查询后结果的分页没做处理,下面我们来改造一下这个分页程序。
二、准备工作
首先准备一个数据源
数据源准备
1 public class News
2 {
3 public int ID { get; set; }
4 public string Author { get; set; }
5 public string Title { get; set; }
6 public DateTime CreateTime { get; set; }
7 }
8 public class ListNews
9 {
10 public static List<News> GetList()
11 {
12 List<News> list = new List<News>();
13 list.Add(new News { ID = 1, Author = "lfm1", Title = "中华人民共和国60周年", CreateTime = DateTime.Now });
14 list.Add(new News { ID = 2, Author = "lfm2", Title = "中华人民共和国61周年", CreateTime = DateTime.Now.AddHours(1) });
15 list.Add(new News { ID = 3, Author = "lfm3", Title = "中华人民共和国62周年", CreateTime = DateTime.Now.AddHours(2) });
16 list.Add(new News { ID = 4, Author = "lfm3", Title = "中华人民共和国63周年", CreateTime = DateTime.Now.AddHours(3) });
17 list.Add(new News { ID = 5, Author = "lfm2", Title = "中华人民共和国64周年", CreateTime = DateTime.Now.AddHours(4) });
18 list.Add(new News { ID = 6, Author = "lfm1", Title = "中华人民共和国60周年", CreateTime = DateTime.Now });
19 list.Add(new News { ID = 7, Author = "lfm2", Title = "中华人民共和国61周年", CreateTime = DateTime.Now.AddHours(1) });
20 list.Add(new News { ID = 8, Author = "lfm3", Title = "中华人民共和国62周年", CreateTime = DateTime.Now.AddHours(2) });
21 list.Add(new News { ID = 9, Author = "lfm3", Title = "中华人民共和国63周年", CreateTime = DateTime.Now.AddHours(3) });
22 list.Add(new News { ID = 10, Author = "lfm2", Title = "中华人民共和国64周年", CreateTime = DateTime.Now.AddHours(4) });
23 list.Add(new News { ID = 11, Author = "lfm2", Title = "中华人民共和国64周年", CreateTime = DateTime.Now.AddHours(4) });
24 list.Add(new News { ID = 12, Author = "lfm1", Title = "中华人民共和国60周年", CreateTime = DateTime.Now });
25 list.Add(new News { ID = 13, Author = "lfm2", Title = "中华人民共和国64周年", CreateTime = DateTime.Now.AddHours(4) });
26 list.Add(new News { ID = 14, Author = "lfm1", Title = "中华人民共和国60周年", CreateTime = DateTime.Now });
27 list.Add(new News { ID = 15, Author = "lfm2", Title = "中华人民共和国64周年", CreateTime = DateTime.Now.AddHours(4) });
28 list.Add(new News { ID = 16, Author = "lfm1", Title = "中华人民共和国60周年", CreateTime = DateTime.Now });
29
30 return list;
31 }
32 }
然后添加一个View:
View
1 <%Html.BeginForm();%>
2 Title:<%=Html.TextBox("title",Request.Form["title"]??Request.QueryString["title"]) %>
3 Author:<%=Html.TextBox("author",Request.Form["author"]??Request.QueryString["author"]) %>
4 <input type="submit" value="查询" />
5 <%Html.EndForm(); %>
6 <%=Html.Grid(Model).Columns(column=>{
7 column.For(x=>x.ID).Named("News ID");
8 column.For(x => Html.ActionLink(x.Title, "NewsDetils", new { newsId = x.ID })).DoNotEncode();
9 column.For(x => x.Author).Header("<th>"+Html.ActionLink("作者","CustomPager",new{desc = Convert.ToBoolean(ViewData["desc"]),sortName="Author"})+"</th>");
10 column.For(x=>x.CreateTime);
11 })
12 %>
13
14 <%= Html.Pager(Model,ViewData["search"])%>
这里的分页代码和Contrib中略有不同,一会儿我们来讲解这个不同的原因。
添加一个Controller:
Controller
1 public ActionResult CustomPager(int? page)
2 {
3 int pageSize = 3;
4 int pageNumber = page ?? 1;
5 var list = ListNews.GetList()
6 .Where(p => p.Title.Contains(Request.QueryString["title"] ?? ""))
7 .Where(p => p.Author.Contains(Request.QueryString["author"] ?? ""));
8
9 var pageList=list.Skip((pageNumber - 1) * pageSize).Take(pageSize);
10 int total = list.Count();
11 CustomPagination<News> customes = new CustomPagination<News>(pageList, pageNumber, pageSize, total);
12
13 return View(customes);
14 }
15 [AcceptVerbs(HttpVerbs.Post)]
16 public ActionResult CustomPager(FormCollection formCollection)
17 {
18 int pageSize = 3;
19 int pageNumber = 1;
20 var list = ListNews.GetList().Where(p => p.Title.Contains(Request.Form["title"]))
21 .Where(p => p.Author.Contains(Request.Form["author"]));
22 int total = list.Count();
23 var pageList = list.Skip((pageNumber - 1) * pageSize).Take(pageSize);
24 CustomPagination<News> customes = new CustomPagination<News>(pageList, pageNumber, pageSize, total);
25 Dictionary<string, string> d = new Dictionary<string, string>();
26 d.Add("title", Request.Form["title"]);
27 d.Add("author", Request.Form["author"]);
28 ViewData["Search"] = d;
29 return View(customes);
30 }
注:这部分内容的详细讲解可以参见:ASP.NET MVC实践系列7-Grid实现(下-利用Contrib实现)
三、Contrib的分页源码分析
我们先把Pagination和Pager两个文件夹中的源码copy出来,经过分析我们知道CustomPagination是实现了IPagination接口的集合,我们把数据整合到CustomPagination中就可以使用Pager进行分页了,PaginationExtensions是辅助HtmlHelper使用扩展方法的静态类。
四、Pager类改造
经过分析我们发现Pager是通过ToString()方法将分页字符串输出到前台的,所以我们这里需要先改造Pager的ToString()方法。我们常常希望分页是这样显示的:
上一页 1 2 3 4 5 6 下一页,所以先将ToString()方法改造如下:
ToString方法
1 public override string ToString()
2 {
3 if (_pagination.TotalItems == 0)
4 {
5 return null;
6 }
7
8 var builder = new StringBuilder();
9
10 builder.Append("<div class=" + _pageStyle + ">");
11
12 if (_pagination.PageNumber > 1)
13 builder.Append(CreatePageLink(_pagination.PageNumber - 1, _pagePrev));
14 else
15 builder.Append(CreatePageText(_pagePrev));
16 for (int i = 0; i < _pagination.TotalPages; i++)
17 {
18 var current = i + 1;
19 if (current == _pagination.PageNumber)
20 {
21 builder.Append(CreatePageText(current.ToString()));
22 }
23 else
24 {
25 builder.Append(CreatePageLink(current, current.ToString()));
26 }
27 builder.Append(" ");
28 }
29
30 if (_pagination.PageNumber < _pagination.TotalPages)
31 builder.Append(CreatePageLink(_pagination.PageNumber + 1, _pageNext));
32 else
33 builder.Append(CreatePageText(_pageNext));
34 builder.Append(@"</div>");
35
36 return builder.ToString();
37 }
这里需要交代一下将要实现查询分页的原理,这个方案中我们将会把查询的信息附加到分页的Url上,首先我们会把需要附加的条件添加到一个Dictionary<string, string>类中,然后传给Pager类进行处理。
下面我们来改造一下CreateQueryString方法:
CreateQueryString
1 private string CreateQueryString(NameValueCollection values)
2 {
3 var builder = new StringBuilder();
4 if (_searchValues != null)
5 {
6 builder = GetSearchPage(values);
7 }
8 else
9 {
10 foreach (string key in values.Keys)
11 {
12 if (key == _pageQueryName)
13 //Don't re-add any existing 'page' variable to the querystring - this will be handled in CreatePageLink.
14 {
15 continue;
16 }
17
18 foreach (var value in values.GetValues(key))
19 {
20 builder.AppendFormat("&{0}={1}", key, HttpUtility.UrlEncode(value));
21 }
22 }
23 }
24
25
26 return builder.ToString();
27 }
28 /// <summary>
29 /// 根据传入的_searchValues来组织分页字符串
30 /// </summary>
31 /// <param name="values"></param>
32 /// <returns></returns>
33 private StringBuilder GetSearchPage(NameValueCollection values)
34 {
35 var builder = new StringBuilder();
36 Dictionary<string, string> dictionary = new Dictionary<string, string>();
37 foreach (var item in _searchValues)
38 {
39 dictionary.Add(item.Key, item.Value);
40 }
41 foreach (string key in values.Keys)
42 {
43 if (key == _pageQueryName)
44 //Don't re-add any existing 'page' variable to the querystring - this will be handled in CreatePageLink.
45 {
46 continue;
47 }
48
49 foreach (var value in values.GetValues(key))
50 {
51 if (_searchValues.Keys.Contains(key))
52 {
53 builder.AppendFormat("&{0}={1}", key, HttpUtility.UrlEncode(dictionary[key]));
54 dictionary.Remove(key);
55 }
56 else
57 {
58 builder.AppendFormat("&{0}={1}", key, HttpUtility.UrlEncode(value));
59 }
60
61 }
62
63 }
64 foreach (var item in dictionary)
65 {
66 builder.AppendFormat("&{0}={1}", item.Key, HttpUtility.UrlEncode(item.Value));
67
68 }
69 return builder;
70 }
这里边主要添加的就是这个GetSearchPage方法,这个方法就是根据客户端传入的查询条件来组织显示分页字符串的。
五、缺点:
因为时使用附加url的方式实现的,所以对于查询条件过多的时候可能有问题,有空我会再实现一个post方案供大家参考。另外这里大家还需要注意的就是url中的查询字符串的名字不能重复,如果重复会直接被替换,详见源码。
六、源码下载
我的ASP.NET MVC实践系列
ASP.NET MVC实践系列1-UrlRouting
ASP.NET MVC实践系列2-简单应用
ASP.NET MVC实践系列3-服务器端数据验证
ASP.NET MVC实践系列4-Ajax应用
ASP.NET MVC实践系列5-结合jQuery
ASP.NET MVC实践系列6-Grid实现(上)
ASP.NET MVC实践系列7-Grid实现(下-利用Contrib实现)
其他:
在ASP.NET MVC中对表进行通用的增删改