介绍
借助 AspNet 提供的数据绑定控件我们无需太多的代码甚至不需要代码只要在 VS 中拖拽几下控件进行一些属性的设置便可以实现在Asp时代需要做大量工作才能够实现的分页功能但在实际的应用中尤其是在Web站点程序中我们经常需要更加丰富的用户界面而类似DataList或者 GridView 这样的数据控件往往不能或者很难满足我们的要求此时我们常常求助于 Repeater 控件这样我们依旧会面临分页及其显示的问题
本文不是讲述如何进行数据库分页而将注意力集中在如何实现可定制地 获取页码获取路径显示分页链接并且通过构建一个用户控件来实现代码重用上如果你是一个初学者你可以借鑒一下我的实现方式如果你已经是一位高手不妨提出设计的不足和改进意见
NOTE本文是以接口的实现方式作为讲述这是因为我写这篇文章的时候使用的是接口但我后来又提供了一种更好的使用继承的方式来实现我提供了两个版本的代码下载你可以相互对比着参考
控件组成
为了能迅速提起大家的兴趣可以先点击这个链接看看实际的效果
x
IUrlManager 接口
想一想如果你在设计一个可重用的分页用户控件你面临的问题是什么每个人获取页码的方式都不同例如你的站点URL可能是类似这样的 Defaultaspxpage= 而另外一个站点的URL 是这样的 Defaultaspxp=更有一些可能根本不使用 QueryString 来获取页码它们的URL可能是这样的 DefaultaspxDefaultaspx 等等获取页码的方式不同根据页码产生链接地址的方法自然也不相同按照封装变化的思想我们应该将这变化的部分取出来建一个 IUrlManager 接口
public interface IUrlManager
{
int CurrentPageIndex{ get; } // 当前页码
string GetPageUrl(int pageIndex); // 根据 页码 获取页面路径
}
而实际上当前页码不应该大于总页数所以获取当前页CurrentPageIndex属性需要能得知 总页数而总页数通常是由 记录数 和 分页大小计算得出这个接口实际上应该是这样
public interface IUrlManager
{
int CurrentPageIndex{ get; } // 当前页码
string GetPageUrl(int pageIndex); // 根据 页码 获取页面路径
int PageCount { get; } // 总页数
int RecordCount { get; } // 记录总数
int PageSize { get; } // 分页大小
}
要求在 IUrlManager里实现总页数PageCount属性可能有点奇怪但仔细想一想就明白了
控件本身需要知道总共有多少页然后才能判断显示多少链接数我们的用户控件部分仅仅是进行一系列链接的显示它仅需要知道 当前页码总页码以及链接的URL 就足够了 因为 当前页码 应该小于等于 总页码所以获取当前页码 CurrentPageIndex 也需要知道 总页码 而为什么要实现 RecordSize 和 PageSize 属性是一个值得思考的地方
总页码 是根据 记录数 和 分页大小 算得的所以对于实现 IUrlManager 接口的类我们总是需要提供 记录数 和 分页大小何不简单地提供一个属性来对它们进行访问而其他的地方(比如某个方法)有可能会需要这两个值此时我们可以直接将 IUrlManager 作为参数传进去
问题是如果这个接口仅仅是用于 分页控件那么实现 RecordSize 和 PageSize 是不必要的我们也不应该在控件上设置 RecordCountPageSize这里的粒度可能大了
DefaultUrlManager 类
现在 所有获取页码 及 根据页码获取路径 的逻辑都可以放在实现了这个接口的类中如果你想使用这个控件你需要提供一个实现了IUrlManger接口的类为了使控件立即可用我在这里提供了一个默认实现我管它叫做 DefaultUrlManger它通过RequestQueryString获取页码并默认以Page作为参数
public class DefaultUrlManager : IUrlManager {
private HttpContext context;
private Regex reg;
private string queryParam; // QueryString 参数名称
private int currentPageIndex; // 当前页
private int pageCount; // 总页数
private int recordCount; // 记录总数
private int pageSize; // 分页大小
// 构造函数
public DefaultUrlManager(int recordCount int pageSize string queryParam)
{
if (recordCount < )
throw new ArgumentOutOfRangeException(recordCount 应该大于等于 !);
if (pageSize < = )
throw new ArgumentOutOfRangeException(pageSize 应该大于 !);
if (stringIsNullOrEmpty(queryParam))
throw new ArgumentNullException(queryParam 不能为空!);
// 设置私有变量
thisrecordCount = recordCount;
thispageSize = pageSize;
thisqueryParam = queryParam;
context = HttpContextCurrent;
string pattern = @(< r>[&] + queryParam + @=)[^&]*;
reg = new Regex(pattern RegexOptionsIgnoreCase);
// 如果记录数为至少也显示一页
if (recordCount == ) {
currentPageIndex = ;
pageCount = ;
} else {
// 设置总页数
double recordCount = ConvertToDouble(recordCount);
double pageSize = ConvertToDouble(pageSize);
pageCount = ConvertToInt(MathCeiling(recordCount / pageSize));
// 设置当前页码
string queryIndex = contextRequestQueryString[queryParam];
if (stringIsNullOrEmpty(queryIndex))
currentPageIndex = ;
else {
try {
currentPageIndex = MathAbs(intParse(queryIndex));
if (currentPageIndex == )
currentPageIndex = ;
if (currentPageIndex > pageCount)
currentPageIndex = pageCount;
}
catch {
currentPageIndex = ;
}
}
}
}
// 默认以 Page 作为 QueryString 的参数
public DefaultUrlManager(int recordCount int pageSize) : this(recordCount pageSize Page) { }
// 默认以 作为 PageSize
public DefaultUrlManager(int recordCount string queryParam) : this(recordCount queryParam) { }
// 默认以 Page 作为 QueryString 的参数以 作为分页大小
public DefaultUrlManager(int recordCount) : this(recordCount ) { }
public string GetPageUrl(int pageIndex) {
string pageUrl = contextRequestRawUrl;
// 如果找到匹配也就是URL中含有类似 page= 或者 &page= 这样的字符串
// 则对后面的数值进行替换
if (regIsMatch(pageUrl)) {
pageUrl = regReplace(pageUrl ${r} + pageIndexToString());
} else {
string queryString = contextRequestUrlQuery;
if (stringIsNullOrEmpty(queryString))
pageUrl += + queryParam + = + pageIndexToString();
else
pageUrl += & + queryParam + = + pageIndexToString();
}
return pageUrl;
}
public int CurrentPageIndex
{
get { return currentPageIndex; }
}
public int PageCount
{
get { return pageCount; }
}
public int RecordCount
{
get { return recordCount; }
}
public int PageSize
{
get { return pageSize; }
}
}
Pagerascx 文件
由于我们的链接是动态生成的所以我们大部分的代码都会存在于 Pagerascxcs 中在Pagerascx 文件中我们只提供一个装链接的