拼吾爱程序人生.Net编程Asp.Net Asp.Net 可自定义分页用户控件

1  /  1  页   1 跳转 查看:591

Asp.Net 可自定义分页用户控件

Asp.Net 可自定义分页用户控件

文/JimmyZhang  出处/博客园

介绍

借助 Asp.Net 提供的数据绑定控件,我们无需太多的代码,甚至不需要代码,只要在 VS2005 中拖拽几下控件,进行一些属性的设置,便可以实现在Asp时代需要做大量工作才能够实现的分页功能。但在实际的应用中,尤其是在Web站点程序中,我们经常需要更加丰富的用户界面,而类似DataList或者 GridView 这样的数据控件往往不能或者很难满足我们的要求。此时,我们常常求助于 Repeater 控件,这样我们依旧会面临分页及其显示的问题。

本文不是讲述如何进行数据库分页,而将注意力集中在如何实现可定制地 获取页码、获取路径、显示分页链接,并且通过构建一个用户控件来实现代码重用上。这个用户控件我自己正在使用,如果你是一个初学者,你可以借鉴一下我的实现方式;如果你已经是一位高手,不妨提出设计的不足和改进意见。

控件组成

为了能迅速提起大家的兴趣,可以先点击这个链接,看看实际的效果:

http://www.tracefact.net/Demo/Pager/Default.aspx

IUrlManager 接口

想一想如果你在设计一个可重用的分页用户控件,你面临的问题是什么?每个人获取页码的方式都不同,例如,你的站点URL可能是类似这样的 Default.aspx?page=1 ,而另外一个站点的URL 是这样的 Default.aspx?p=1。更有一些可能根本不使用 QueryString 来获取页码,它们的URL可能是这样的 Default-1.aspx、Default-2.aspx 等等。获取页码的方式不同,根据页码产生链接地址的方法自然也不相同。按照封装变化的思想,我们应该将这变化的部分取出来,建一个 IUrlManager 接口:

public interface IUrlManager
{
    int GetCurrentPageIndex();              // 获取 当前页面 的页码
    string GetPageUrl(int pageIndex);      // 根据 页码 获取页面路径
}

DefaultUrlManager 类

现在 所有获取页码 及 根据页码获取路径 的逻辑都可以放在实现了这个接口的类中。如果你想使用这个控件,你需要提供一个实现了IUrlManger接口的类。为了使控件立即可用,我在这里提供了一个默认实现,我管它叫做 DefaultUrlManger。它通过Request.QueryString获取页码,并默认以"Page"作为参数。

public class DefaultUrlManager : IUrlManager {
    private HttpContext context;
    private Regex reg;
    private string queryParam;

    public DefaultUrlManager(string queryParam) {
      this.queryParam = queryParam;
      context = HttpContext.Current;     
      string pattern = @"(?<r1>[?&]" + queryParam + @"=)[^&]+";
      reg = new Regex(pattern, RegexOptions.IgnoreCase);
    }

    public DefaultUrlManager() : this("Page") { }

    public string GetPageUrl(int pageIndex) {
      string pageUrl = context.Request.RawUrl;

      // 如果找到匹配,也就是URL中含有类似 ?page=3 或者 &page=4 这样的字符串
      // 则对后面的数值进行替换
      if (reg.IsMatch(pageUrl)) {       
          pageUrl = reg.Replace(pageUrl, "${r1}" + pageIndex.ToString());
      } else {
         
          string queryString = context.Request.Url.Query;

          if (string.IsNullOrEmpty(queryString))
              pageUrl += "?" + queryParam + "=" + pageIndex.ToString();
          else
              pageUrl += "&" + queryParam + "=" + pageIndex.ToString();
      }

      return pageUrl;
    }

    public int GetCurrentPageIndex() {

      string queryIndex = context.Request.QueryString[queryParam];

      if (string.IsNullOrEmpty(queryIndex))
          return 1;
      else {
          int pageIndex;
          try {
              pageIndex = Math.Abs(int.Parse(queryIndex));
          } catch {
              pageIndex = 1;
          }

          return pageIndex;
      }
    }
}

Pager.ascx 文件

由于我们的链接是动态生成的,所以我们大部分的代码都会存在于 Pager.ascx.cs 中,在Pager.ascx 文件中,我们只提供一个装链接的容器:

<%@ Control Language="C#" AutoEventWireup="true" CodeFile="Pager.ascx.cs" Inherits="CustomPager" %>
<asp:Panel ID="pnPager" runat="server" CssClass="Pager"></asp:Panel>

Pager.ascx.cs 文件

我们对于页面的显示的主要实现都放置在了这个文件中,我在文件中做了大量注释,这里就不再文字描述了:

using System;
// ... 略

public partial class CustomPager : System.Web.UI.UserControl
{
    private int pageSize = 10;              // 分页大小
    private int recordCount;            // 记录总数
    private int pageCount;                  // 总页数

    private int currentPage;            // 当前页的页码
    private int previousPageCount = 5;      // 当前页之前可以显示的最多条目数,大于此条目的将被隐藏
    private int afterPageCount = 4;        // 当前页之后可以显示的最多条目数,大于此条目的将被隐藏

    private bool showPrevious = false;      // 是否显示 上一页、第一页 的链接
    private bool showNext = false;          // 是否显示 下一页、最末页 的链接

    private int startPage;                  // 显示的第一页 的 页码
    private int endPage;                // 显示的最末页 的 页码

    private IUrlManager urlManager;        // 设置接口
   
    public int RecordCount
    {
      get { return recordCount; }
      set { recordCount = value; }
    }

    public int PageSize
    {
      get { return pageSize; }
      set { pageSize = value; }
    }

    public int PreviousPageCount
    {
      get { return previousPageCount; }
      set { previousPageCount = value; }
    }

    public int AfterPageCount
    {
      get { return afterPageCount; }
      set { afterPageCount = value; }
    }
   
    public IUrlManager UrlManager
    {
      get { return urlManager; }
      set { urlManager = value; }
    }

    // 设置 pnPager Div 的 CssClass 属性,通过它来为控件定义样式
    public string CssClass {
      set { pnPager.CssClass = value; }
      get { return pnPager.CssClass; }
    }

   
    private void RenderPager()
    {
      if (urlManager == null)
      {
          urlManager = new DefaultUrlManager();
      }

      // 获取页数
      double recordCount2 = Convert.ToDouble(recordCount);
      double pageSize2 = Convert.ToDouble(pageSize);
      pageCount = Convert.ToInt32(Math.Ceiling(recordCount2 / pageSize2));

      // 获取当前页
      currentPage = urlManager.GetCurrentPageIndex();
      if (currentPage < 0)
          currentPage = 1;
      else if (currentPage > pageCount)
          currentPage = pageCount;

      SetStartPage();
      SetEndPage();
      HyperLink link;

      // 循环打印链接
      for (int i = startPage; i <= endPage; i++)
      {
          if (showPrevious) // 如果需要显示前一页、第一页链接
              AddPreviousLink(urlManager);
         

          link = new HyperLink();
          if (i == currentPage)
              link.CssClass = "CurrentPage";

          link.Text = i.ToString();
          link.NavigateUrl = urlManager.GetPageUrl(i);
          pnPager.Controls.Add(link);

          if (i == endPage && showNext)  // 如果需要显示 下一页、最末页 链接
              AddNextLink(urlManager);       
      }

      Label lbCount = new Label();
      lbCount.Text = String.Format(" ( 第<b>{0}</b>页/共<b>{1}</b>页 )", currentPage, pageCount);
      pnPager.Controls.Add(lbCount);
    }


    // 添加“第一页”,“上一页”的连接
    private void AddPreviousLink(IUrlManager urlManager)
    {
      HyperLink first = new HyperLink();
      first.CssClass = "PagerIcon";
      first.Text = "<<";
      first.ToolTip = "第一页";
      first.NavigateUrl = urlManager.GetPageUrl(1);
      pnPager.Controls.Add(first);

      HyperLink previous = new HyperLink();
      previous.CssClass = "PagerIcon";
      previous.Text = "<";
      previous.ToolTip = "上一页";
      previous.NavigateUrl = urlManager.GetPageUrl(currentPage - 1);
      pnPager.Controls.Add(previous);

      showPrevious = false; // 只显示一次
    }


    // 添加 “下一页”、“最末页” 的链接
    private void AddNextLink(IUrlManager urlManager)
    {
      HyperLink next = new HyperLink();
      next.CssClass = "PagerIcon";
      next.Text = ">";
      next.ToolTip = "下一页";
      next.NavigateUrl = urlManager.GetPageUrl(currentPage + 1);
      pnPager.Controls.Add(next);

      HyperLink last = new HyperLink();
      last.CssClass = "PagerIcon";
      last.Text = ">>";
      last.ToolTip = "最末页";
      last.NavigateUrl = urlManager.GetPageUrl(pageCount);
      pnPager.Controls.Add(last);

      showNext = false; // 可有可无,程序会跳出循环
    }


    // 根据当前页,当前页之前可以显示的页数,算得从第几页开始进行显示
    private void SetStartPage()
    {
      // 如果当前页小于 它前面所可以显示的条目数,那么显示第一页就是实际的第一页
      if (currentPage <= previousPageCount)
      {
          startPage = 1;
      } else // 这种情况下 currentPage 前面总是能显示完,要根据后面的长短确定是不是前面应该多显示
      {
          if(currentPage > previousPageCount+1)
              showPrevious = true;

          int linkLength = (pageCount - currentPage + 1) + previousPageCount;

          int startPage = currentPage - previousPageCount;

          while (linkLength < previousPageCount + afterPageCount + 1 && startPage > 1)
          {
              linkLength++;
              startPage--;
          }
                     
          this.startPage = startPage;
      }
    }
   
    // 根据CurrentPage、总页数、当前页之后长度 算得显示的最末页是 第几页
    private void SetEndPage()
    {
      // 如果当前页加上它之后可以显示的页数 大于 总页数,那么显示的最末页就是实际的最末页
      if (currentPage + afterPageCount >= pageCount)
      {
          endPage = pageCount;
      } else // 这种情况下 currentPage后面的总是可以显示完,要根据前面的长短确定是不是后面应该多显示
      {
          int linkLength = (currentPage - startPage + 1) + afterPageCount;
     
          int endPage = currentPage + afterPageCount;

          while (linkLength < previousPageCount + afterPageCount + 1 && endPage < pageCount)
          {
              linkLength++;
              endPage++;
          }

          if (endPage < pageCount)
              showNext = true;

          this.endPage = endPage;
      }
    } 

    protected void Page_Load(object sender, EventArgs e)
    {
      RenderPager();
    }
}

友情提示:此文并不表示本站肯定持有相同观点,转载请注明出处。
 您可能对 [Asp.Net] 的这些文章也感兴趣:

利用WebClient和WebRequest类获得网页源代码C#  ASP.NET安全身份验证的实现
在.NET中创建弹出窗口的方法  为ASP.NET封装的SQL数据库访问类
用ASP.NET建立一个在线RSS新闻聚合器  用ObjectSpaces重建IBuySpy的数据访问层
MonoRail:页面交互的输入输出方式总结  asp.net(C#)海量数据表高效率分页算法
用Guid为ASP.NET中的上传文件命名  RegularExpressionValidator
带你走进ASP.NET(1)  Asp.Net学习资料(中文)
C#2.0 的新增功能学习  防止页面被多次提交
DataGrid鼠标事件处理  利用客户端缓存对网站进行优化
使用RangeValidator  在ASP.NET中执行URL重写
asp向asp.net应用程序的转变过程  [Podcast推荐]--ASP.NET & .NET
 

回复:Asp.Net 可自定义分页用户控件

设置样式

控件没有提供任何的样式控制,对于样式,你唯一能做的就是通过它的CssClass属性来设置由Panel控件生成的Div的Class,然后利用这个Class编写样式表来控制显示。如果有必要,你还可以通过利用PagerIcon这个Css类来控制“上一页”、“下一页”、“第一页”、“最末页”的显示;通过 CurrentPage 这个Css类来控制 当前页 的显示。由此,在所有使用这个控件的页面,你都应该包含有控制控件样式的样式表。

这里,我提供了一个默认的实现(在你不设置控件的CssClass属性的时候,默认为Pager):

.Pager a{
    display:block;
    border:1px solid #ccc;
    float:left;
    padding:4px 5px;
    text-decoration:none;
    text-align:center;
    margin:0 1px;
}

.Pager a.CurrentPage{
    background:#999;
    color:#eee;
}

.Pager span{
    position:relative;
    top:6px;
}

控件的使用

好了,现在一切都OK了,让我们看看控件如何使用。我们以一种最简单的方式开始,再以一种最复杂的方式开始。

声明式使用

直接拖拽控件到页面上(比如Default.aspx),然后设置一下它的RecordCount值就可以了。生成的页面代码如下:

// ... 略
<%@ Register Src="UserControl/Pager.ascx" TagName="Pager" TagPrefix="uc1" %>
// ... 略
<uc1:Pager id="Pager1" runat="server" RecordCount="337"></uc1:Pager>

动态创建式使用

我们也可以编写后置代码,然后来动态地使用它:

public partial class _Default : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack) {
            CustomPager pager = (CustomPager)LoadControl(@"~/UserControl/Pager.ascx");
            pager.CssClass = "GreenStyle";  // 设置颜色       
            pager.UrlManager = new DefaultUrlManager("P");    // 设置根据Request.QueryString获取页码的参数
            // 如果你实现了自己的IUrlManager接口,这里可能是这样:
            // pager.UrlManager = new YourUrlManger();
            pager.RecordCount = 132;        // 设置记录数
            pager.PageSize = 7;                // 设置分页大小
            pager.PreviousPageCount = 3;      // 设置当前页之前显示的最大链接数
            pager.AfterPageCount = 3;          // 设置当前也之后可以显示的最大链接数

            // 将控件加入到页面上
            phHolder.Controls.Add(pager);
        }
    }
}

注意到这里,由于我们使用了新的CssClass样式,所以你也需要提供基于GreenStyle的样式表,我是这样提供的:

.GreenStyle a{
    display:block;
    border:1px solid #9cba39;
    float:left;
    padding:4px 5px;
    text-decoration:none;
    text-align:center;
    margin:0 1px;
    color:#9cba39
}

.GreenStyle a.CurrentPage{
    background:#C5D985;
    color:#fff;
}

.GreenStyle span{
    position:relative;
    top:6px;
}

.GreenStyle span b{
    color:#C33;
}

总结

本文我们实现了Asp.Net中的一个常见的功能,通过一个用户控件来实现数据分页的页面层以达到代码重用的目的。

我们通过实现 IUrlManager 接口来封装了不同情况下根据URL获取页码的方法。在用户控件中我们实现了主要的逻辑,并调用了实现IUrlManager的类的方法。最后,我们还看了如何通过CSS来控制控件的显示。

希望这篇文章能带给你帮助。
 
1  /  1  页   1 跳转

快速回复帖子

标题
禁用 URL 识别
禁用表情
禁用 Discuz!NT 代码
使用个人签名
  [完成后可按 Ctrl+Enter 无刷新发布]  

版权所有 拼吾爱程序人生 

Powered by Discuz!NT 2.1.202   Copyright © 2001-2008 Comsenz Inc. 鄂ICP备07500843号
返顶部