[MVC]ASP.NET MVC实践系列8-对查询后分页处理的解决方案

转载:http://www.cnblogs.com/nuaalfm/archive/2009/11/18/1605364.html

一、前言:

GridView中的分页是用post做的,所以将查询表单中的内容可以存到ViewState中,翻页的时候可以利用,实现起来就比较容易些,而 在mvc中这些就要我们自己来做了,Contrib中的分页只能应付简单应用,对于查询后结果的分页没做处理,下面我们来改造一下这个分页程序。

二、准备工作

首先准备一个数据源


 1 public class News
 2 {
 3     public int ID { getset; }
 4     public string Author { getset; }
 5     public string Title { getset; }
 6     public DateTime CreateTime { getset; }
 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:


 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:


 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<stringstring> d = new Dictionary<stringstring>();
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()方法改造如下:


 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方法:

 


 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("&amp;{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<stringstring> dictionary = new Dictionary<stringstring>();
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("&amp;{0}={1}", key, HttpUtility.UrlEncode(dictionary[key]));
54                         dictionary.Remove(key);
55                     }
56                     else
57                     {
58                         builder.AppendFormat("&amp;{0}={1}", key, HttpUtility.UrlEncode(value));
59                     }
60 
61                 }
62 
63             }
64             foreach (var item in dictionary)
65             {
66                 builder.AppendFormat("&amp;{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中对表进行通用的增删改

赞(0) 打赏
分享到: 更多 (0)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏