在这篇MVC学习(四)几种分页的实现(2)博文中,根据URL中传入的两个参数(页码数,首页、上一页、下一页、末页的标记符)来获得对应的分页数据,
只是传入的参数太多,调用起来不太方便(标记符不能够写错,需要添加新的路由),因此,如果URL只传入页码数就太好,顺着这个思路,有了第三种分页方式。
实现分页形式如下图所示。
下面说说我的思路吧。
为了在试图文件中呈现<input type="text" ...> ,我们需要写上代码@Html.TextBox(Asp.net MVC 3语法),为了呈现Lable,需要写@Html.Label,
这里的@Html,有一个管理它的类 HtmlHelper。为了使用方便,我决定对HtmlHelper类进行扩展。
考虑到有些页面不需要“上一页”,“下一页”之间的“100001”,因此,决定由两种呈现形式,一个是普通的分页,一个是带数字的分页,只有两种分页模式,新建一个枚举类型PageMode,代码如下
面向对象,对象总是很重要的,因此,页面对象是首先需要抽象出来的。
我希望展现的形式是 “总共XX条记录,共XX页,当前第X页 首页 1 2... 上一页 下一页 末页”,想想这段话中,“记录数量”,“共多少页”,“第几页”,还有一条隐形“每页展示数据的大小”,因此,抽象出页面对象PagerInfo(TotalPageCount可以放入这个类中),代码如下。
public class PagerInfo { public int RecordCount { get; set; } public int CurrentPageIndex { get; set; } public int PageSize { get; set; } }
第一步,如何扩展HtmlHelper。
首先,给大家看看微软如何@Html.Label的代码,看下面的截图
在研究了这段代码后,就可以写一个普通的HtmlHelper扩展了,代码如下
public static MvcHtmlString Pager(this HtmlHelper helper, string id, int currentPageIndex, int pageSize, int recordCount, object htmlAttributes, string className, PageMode mode) { TagBuilder builder = new TagBuilder("table"); builder.IdAttributeDotReplacement = "_"; builder.GenerateId(id); builder.AddCssClass(className); builder.MergeAttributes(new RouteValueDictionary(htmlAttributes)); return builder.ToMvcHtmlString(TagRenderMode.Normal); }
"string id"表示这个控件的id号,“int currentPageIndex”表示需要显示第几页数据的页码,
“int pageSize"表示每页显示数据的大小,”object htmlAttributes“表示属性, ”string className“表示样式属性。
看了我的HtmlHepler扩展代码,在与微软的原始代码比较以后,会发现我少了一行重要的代码,就是”tagBuilder.SetInnerText(str);“,即控件在View
的呈现形式。无论是asp.net WebForm页面的服务器控件,还是类似"<input type="text" runat="server">”控件,或者是asp.net MVC的@Html.Label,
他们在页面的都是以字符串的形式展现。
有了这个思路,写出普通的分页形式就比较简单了。
我们只需要给TagBuilder给予正确的字符串就行了。
1、首先获得总的记录数,总页数
总记录数 int pageCount =Convert.ToInt32(Math.Ceiling((double)RecordCount / (double)PageSize));//获得总页数
2、普通分页如何实现
假设我们的url形式为 “http://localhost:11507/Home/FY3?page=2”,那么下一页的url形式便是“http://localhost:11507/Home/FY3?page=3”,因此,我们需要得到传来的绝对路径,不含任何参数。然后根据传来的当前页码数,判断是否有下一页,上一页,并且得到格式化后的url。
这里我先理一理页码数如何传入HtmlHelper中的。
首先,Controller从URL中获取CurrentPageIndex,然后放入PageInfo对象,并且获得分页数据(InfoSource);
然后,我们将InfoSource与PageInfo两个对象放入一个泛型容器PagerQuery<T>,返回给View;
最后,HtmlHelper根据View页面中的对象获得所需参数。
现在回到HtmlHelper的扩展实现。
获得我们需要ULR格式化字符串,如下代码。
var url=new StringBuilder();
url.Append(HttpContext.Current.Request.Url.AbsolutePath+"?page={0}");
我希望展现的形式是 “总共XX条记录,共XX页,当前第X页 首页 上一页 下一页 末页”。现在开始拼字符串。
var sb=new StringBuilder();
sb.Append("<tr><td>");
sb.AppendFormat("总共{0}条记录,共{1}页,当前第{2}页 ",RecordCount,pageCount,currentPageIndex);
//RecordCount,currentPageIndex 值通过PagerInfo传递过来
if(currentPageIndex==1{
sb.Append("<span>首页</span> ";) //如果第一页 不需要给首页真实的链接
}
else{
var url1=string.Format(url.ToString(),1); //格式化URL 得到第一页的url “http://localhost:11507/Home/FY3?page=1”
sb.AppendFormat("<span><a href={0} 首页</a></span> ",url1);
}
如何类推,可得到上一页、下一页、末页的链接。
那么,如果上一页与下一页需要显示数字,怎么办呢? 这里,默认显示10个数字(如果页数不够,就按实际页数显示)
现在,可以得到扩展标签代码,如下
public static MvcHtmlString Pager(this HtmlHelper helper, string id, int currentPageIndex, int pageSize, int recordCount, object htmlAttributes, string className, PageMode mode) { TagBuilder builder = new TagBuilder("table"); builder.IdAttributeDotReplacement = "_"; builder.GenerateId(id); builder.AddCssClass(className); builder.MergeAttributes(new RouteValueDictionary(htmlAttributes)); builder.InnerHtml = GetNormalPage(currentPageIndex, pageSize, recordCount, mode); return builder.ToMvcHtmlString(TagRenderMode.Normal); } static MvcHtmlString ToMvcHtmlString(this TagBuilder tagBuilder, TagRenderMode renderMode) { return new MvcHtmlString(tagBuilder.ToString(renderMode)); }
得到分页字符串代码了,如下
那么,承载数据的容器时什么呢,因为Model是会随时变化的(泛型类最佳实现),代码如下
public class PagerQuery<T> : List<T> { public PagerQuery(PagerInfo pager, IEnumerable<T> source) { this.Pager = pager; int BeforePageIndex = pager.CurrentPageIndex - 1; if (BeforePageIndex < 0) { BeforePageIndex = 1; } var entityList = source.Skip((BeforePageIndex) * pager.PageSize).Take(pager.PageSize); AddRange(entityList); } public PagerInfo Pager { get; set; } }
Controller代码如下
View代码如下
VS 2010 MVC3,配置好数据库后,运行即可,源代码点此下载。
我感觉,第三种分页形式是很完美的,只是重复从第一页跳到最后一页再最后一页跳至第一页,分页缓慢,查看资源管理器,内存被占了很多,未曾释放,因此,
希望各位可以告诉我高效的改进方法~~~