一前言
GridView中的分页是用post做的所以将查询表单中的内容可以存到ViewState中翻页的时候可以利用实现起来就比较容易些而在mvc中这些就要我们自己来做了Contrib中的分页只能应付简单应用对于查询后结果的分页没做处理下面我们来改造一下这个分页程序
二准备工作
首先准备一个数据源
数据源准备
public class News
{
public int ID { get; set; }
public string Author { get; set; }
public string Title { get; set; }
public DateTime CreateTime { get; set; }
}
public class ListNews
{
public static List<News> GetList()
{
List<News> list = new List<News>();
listAdd(new News { ID = Author = lfm Title = 中华人民共和国周年 CreateTime = DateTimeNow });
listAdd(new News { ID = Author = lfm Title = 中华人民共和国周年 CreateTime = DateTimeNowAddHours() });
listAdd(new News { ID = Author = lfm Title = 中华人民共和国周年 CreateTime = DateTimeNowAddHours() });
listAdd(new News { ID = Author = lfm Title = 中华人民共和国周年 CreateTime = DateTimeNowAddHours() });
listAdd(new News { ID = Author = lfm Title = 中华人民共和国周年 CreateTime = DateTimeNowAddHours() });
listAdd(new News { ID = Author = lfm Title = 中华人民共和国周年 CreateTime = DateTimeNow });
listAdd(new News { ID = Author = lfm Title = 中华人民共和国周年 CreateTime = DateTimeNowAddHours() });
listAdd(new News { ID = Author = lfm Title = 中华人民共和国周年 CreateTime = DateTimeNowAddHours() });
listAdd(new News { ID = Author = lfm Title = 中华人民共和国周年 CreateTime = DateTimeNowAddHours() });
listAdd(new News { ID = Author = lfm Title = 中华人民共和国周年 CreateTime = DateTimeNowAddHours() });
listAdd(new News { ID = Author = lfm Title = 中华人民共和国周年 CreateTime = DateTimeNowAddHours() });
listAdd(new News { ID = Author = lfm Title = 中华人民共和国周年 CreateTime = DateTimeNow });
listAdd(new News { ID = Author = lfm Title = 中华人民共和国周年 CreateTime = DateTimeNowAddHours() });
listAdd(new News { ID = Author = lfm Title = 中华人民共和国周年 CreateTime = DateTimeNow });
listAdd(new News { ID = Author = lfm Title = 中华人民共和国周年 CreateTime = DateTimeNowAddHours() });
listAdd(new News { ID = Author = lfm Title = 中华人民共和国周年 CreateTime = DateTimeNow });
return list;
}
}
然后添加一个View
View
<%HtmlBeginForm();%>
Title:<%=HtmlTextBox(titleRequestForm[title]??RequestQueryString[title]) %>
Author:<%=HtmlTextBox(authorRequestForm[author]??RequestQueryString[author]) %>
<input type=submit value=查询 />
<%HtmlEndForm(); %>
<%=HtmlGrid(Model)Columns(column=>{
columnFor(x=>xID)Named(News ID);
columnFor(x => HtmlActionLink(xTitle NewsDetils new { newsId = xID }))DoNotEncode();
columnFor(x => xAuthor)Header(<th>+HtmlActionLink(作者CustomPagernew{desc = ConvertToBoolean(ViewData[desc])sortName=Author})+</th>);
columnFor(x=>xCreateTime);
})
%>
<%= HtmlPager(ModelViewData[search])%>
这里的分页代码和Contrib中略有不同一会儿我们来讲解这个不同的原因
添加一个Controller
Controller
public ActionResult CustomPager(int? page)
{
int pageSize = ;
int pageNumber = page ?? ;
var list = ListNewsGetList()
Where(p => pTitleContains(RequestQueryString[title] ?? ))
Where(p => pAuthorContains(RequestQueryString[author] ?? ));
var pageList=listSkip((pageNumber ) * pageSize)Take(pageSize);
int total = listCount();
CustomPagination<News> customes = new CustomPagination<News>(pageList pageNumber pageSize total);
return View(customes);
}
[AcceptVerbs(HttpVerbsPost)]
public ActionResult CustomPager(FormCollection formCollection)
{
int pageSize = ;
int pageNumber = ;
var list = ListNewsGetList()Where(p => pTitleContains(RequestForm[title]))
Where(p => pAuthorContains(RequestForm[author]));
int total = listCount();
var pageList = listSkip((pageNumber ) * pageSize)Take(pageSize);
CustomPagination<News> customes = new CustomPagination<News>(pageList pageNumber pageSize total);
Dictionary<string string> d = new Dictionary<string string>();
dAdd(title RequestForm[title]);
dAdd(author RequestForm[author]);
ViewData[Search] = d;
return View(customes);
}
注这部分内容的详细讲解可以参见ASPNET MVC实践系列Grid实现(下利用Contrib实现)
三Contrib的分页源码分析
我们先把Pagination和Pager两个文件夹中的源码copy出来经过分析我们知道CustomPagination是实现了IPagination接口的集合我们把数据整合到CustomPagination中就可以使用Pager进行分页了PaginationExtensions是辅助HtmlHelper使用扩展方法的静态类
四Pager类改造
经过分析我们发现Pager是通过ToString()方法将分页字符串输出到前台的所以我们这里需要先改造Pager的ToString()方法我们常常希望分页是这样显示的
上一页 下一页所以先将ToString()方法改造如下
ToString方法
public override string ToString()
{
if (_paginationTotalItems == )
{
return null;
}
var builder = new StringBuilder();
builderAppend(<div class= + _pageStyle + >);
if (_paginationPageNumber > )
builderAppend(CreatePageLink(_paginationPageNumber _pagePrev));
else
builderAppend(CreatePageText(_pagePrev));
for (int i = ; i < _paginationTotalPages; i++)
{
var current = i + ;
if (current == _paginationPageNumber)
{
builderAppend(CreatePageText(currentToString()));
}
else
{
builderAppend(CreatePageLink(current currentToString()));
}
builderAppend( );
}
if (_paginationPageNumber < _paginationTotalPages)
builderAppend(CreatePageLink(_paginationPageNumber + _pageNext));
else
builderAppend(CreatePageText(_pageNext));
builderAppend(@</div>);
return builderToString();
}
这里需要交代一下将要实现查询分页的原理这个方案中我们将会把查询的信息附加到分页的Url上首先我们会把需要附加的条件添加到一个Dictionary<string string>类中然后传给Pager类进行处理
下面我们来改造一下CreateQueryString方法
CreateQueryString
private string CreateQueryString(NameValueCollection values)
{
var builder = new StringBuilder();
if (_searchValues != null)
{
builder = GetSearchPage(values);
}
else
{
foreach (string key in valuesKeys)
{
if (key == _pageQueryName)
//Dont readd any existing page variable to the querystring this will be handled in CreatePageLink
{
continue;
}
foreach (var value in valuesGetValues(key))
{
builderAppendFormat(&{}={} key HttpUtilityUrlEncode(value));
}
}
}
return builderToString();
}
/// <summary>
/// 根据传入的_searchValues来组织分页字符串
/// </summary>
/// <param name=values></param>
/// <returns></returns>
private StringBuilder GetSearchPage(NameValueCollection values)
{
var builder = new StringBuilder();
Dictionary<string string> dictionary = new Dictionary<string string>();
foreach (var item in _searchValues)
{
dictionaryAdd(itemKey itemValue);
}
foreach (string key in valuesKeys)
{
if (key == _pageQueryName)
//Dont readd any existing page variable to the querystring this will be handled in CreatePageLink
{
continue;
}
foreach (var value in valuesGetValues(key))
{
if (_searchValuesKeysContains(key))
{
builderAppendFormat(&{}={} key HttpUtilityUrlEncode(dictionary[key]));
dictionaryRemove(key);
}
else
{
builderAppendFormat(&{}={} key HttpUtilityUrlEncode(value));
}
}
}
foreach (var item in dictionary)
{
builderAppendFormat(&{}={} itemKey HttpUtilityUrlEncode(itemValue));
}
return builder;
}
这里边主要添加的就是这个GetSearchPage方法这个方法就是根据客户端传入的查询条件来组织显示分页字符串的
五缺点
因为时使用附加url的方式实现的所以对于查询条件过多的时候可能有问题有空我会再实现一个post方案供大家参考另外这里大家还需要注意的就是url中的查询字符串的名字不能重复如果重复会直接被替换详见源码
六源码