在第一種分頁方式中,僅僅實現了分頁,但並未有體現出MVC的優勢,沒有體現出泛型編程思想,尤其在數據量很大的時候,分頁十分緩慢,除此之外,還沒有實現很好的封裝,不是一個通用方法。
因此,我希望只要傳入數據源以及頁碼數(采用泛型編程)便可以實現分頁功能,且使用十分的方便。
下面就講講我的一些理解。
在泛型編程中,數據容器一般繼承了IQueryable或者IEnumerable接口(此例中,數據源暫時繼承了這兩種接口)。
為了調用方法方便,我決定對這兩個接口寫擴展方法。
首先為了實現數據分頁功能,我們常常需要考慮以下六個屬性
總頁數(TotalPage)、總數據量(TotalCount)、當前頁碼(PageIndex)、
一頁顯示數據多少(PageSize)以及上一頁或者下一頁(IsPreviousPage/IsNextPage)。
因此,基於對象屬性,抽象出接口(IPageList),分頁方法必須繼承並實現這些屬性。
接口IPageList代碼如下

public interface IPageList { int TotalPage //總頁數
{ get; } int TotalCount//總數量
{ get; set; } int PageIndex//第幾頁
{ get; set; } int PageSize//一頁顯示幾條數據
{ get; set; } bool IsPreviousPage//是否上一頁
{ get; } bool IsNextPage { get; } }
實現接口,代碼如下:

public class PagedList<T>:List<T>:IPageList { public int TotalPage { return (int)Math.Ceiling((doubule)TotalCount/PageSize); } public int TotalCount { get; set; } public int PageIndex { get; set; } public int PageSize { get; set; } public bool IsPreviousPage { get { return (PageIndex>1); } } public bool IsNextPage { get { ((PageIndex) * PageSize) < TotalCount; } } }
讓我們看看這句代碼" public class PagedList<T>:List<T>:IPageList ",這里我們定義了一個泛型類PagedList<T>,
(其中T是一個關鍵字,T的類型可以是引用類型,也可以是值類)。在本例子,T是一個引用類型,而且是一個Model。
首先寫一個靜態類,然后在這個靜態類中書寫靜態方法。擴展方法使您能夠向現有類型“添加”方法,而無需創建新的派生類型、重新編譯或以其他方式修改原始類型。 擴展方法是一種特殊的靜態方法,因此,擴展方法應該放在一個靜態類中。
好,首先對IQueryable<T>進行擴展,命名方法名稱為 ToPagedList,一步一步的解析。
返回值應該是一個泛型集合,因此,方法名可以這樣寫
public List<T> ToPagedList<T>(this IQueryable<T> source,int? index,int? pageSize){ }
在這里,我們可以看到,數據源的類型是IQueryable<T>,頁碼數index是可空類型(默認第一頁),每頁數據條目pageSize可空類型,默認10條數據。
那么,如何調用這些方法的?
初學泛型編程確實挺麻煩,思考的方式不太一樣,特別是代碼的寫法比較特殊,如果把泛型類當做普通的類來思考,就比較容易。
我們需要一個類的屬性時,怎么去實例化呢(剔除靜態類)? 很顯然,new一個新的實例,然后去調用這個屬性(我們寫web Form頁面寫多了,很少考慮服務器控件是如何初始化的);如果想全部實例化屬性,則需要在重載構造函數中動動手腳了。
那么,我們需要從構造函數中得到什么呢, 這才是重點。
第一,實例化分頁的各個屬性;第二,得到當前頁碼的數據,就這兩件終級任務。
由於我希望傳入數據源以及頁碼數便可獲得分頁數據,且考慮是在Asp.net MVC中,因此,傳入的數據要么是IQueryable<T>,要么是IEnumerable<T>,故完全可以充分利用已經存在的類型屬性為自己服務(相信微軟寫出的代碼運行效率不會太低)。在這里我會重載兩個構造函數,因為傳入的數據源的類型不同。
我們 寫上我們需要的構造函數,第一個參數:數據源,第二個參數:當前頁碼數,第三個參數每頁顯示幾條數據。
這里的數據源很重要,因為要繼承IQueryable或IEnumerable接口(這里需要寫兩個構造函數),以便可以使用不同的數據源。
首先看數據源是IQueryable的構造函數,代碼如下

public PagedList(IQueryable<T> source, int? pageIndex, int? pageSize) { if (pageIndex == null) { pageIndex = 1; }//默認顯示第一頁數據
if (pageSize == null) { pageSize = 10; }//默認每頁顯示10條數據
this.TotalCount = source.Count(); this.PageSize = pageSize.Value; this.PageIndex = pageIndex.Value; if (IsPreviousPage == false) { pageIndex = 1; } if (IsNextPage == false) { pageIndex = TotalPage; } int BeforePageIndex = pageIndex.Value - 1; if (BeforePageIndex < 0) { BeforePageIndex = 0; } AddRange(source.Skip((BeforePageIndex) * pageSize.Value).Take(pageSize.Value)); //如果Index是0會報錯,不能夠是負數
}
這里其實是將某一頁的數據放入了List了,因為PagedList已經繼承了List。
既然PagedList是一個List,那么實例化后返回的值便是我們需要的數據,考慮這點,前面的ToPagedList方法返回的值就需要具體一點,而不是模糊的List<T>,應該是PagedList<T>,因此,用於對IQueryable擴展,方法也應該是靜態方法,修訂后的方法如下

public static class Pagination { /// <summary>
/// 返回第幾頁的數據 /// </summary>
/// <typeparam name="T">返回的數據類型</typeparam>
/// <param name="source">數據源,數據源需繼承IQueryable接口</param>
/// <param name="index">第幾頁</param>
/// <param name="pageSize">每頁顯示的數據條數,默認每頁顯示10條數據</param>
/// <returns></returns>
public static PagedList<T> ToPagedList<T>(this IQueryable<T> source, int? index, int? pageSize) { return new PagedList<T>(source, index, pageSize); } }
分頁類准備好后,就是調用了。直接看代碼吧

public ActionResult FY2(string GoFlag, string PageIndex) { int PageSize = 5; int TotalCount = LzsDB.MyTestPages.Count();//獲得此數據表中數據記錄數
double PageCount = Math.Ceiling((double)TotalCount / (double)PageSize);//獲得總頁數
int NowPageIndex = 1; if (!string.IsNullOrEmpty(PageIndex)) { int ErrorPageIndex = 1; if (!Int32.TryParse(PageIndex, out ErrorPageIndex))//如果不能轉換成整數,則默認當前頁碼為1
{ PageIndex = "1"; } NowPageIndex = Convert.ToInt32(PageIndex);// } GoFlag = string.IsNullOrEmpty(GoFlag) ? "First" : GoFlag; switch (GoFlag) { case "First": ViewBag.P2Index = 1; NowPageIndex = 1; break; case "Pre": ViewBag.P2Index = Convert.ToInt32(PageIndex) - 1; NowPageIndex = Convert.ToInt32(PageIndex) - 1; break; case "Next": ViewBag.P2Index = Convert.ToInt32(PageIndex) + 1; NowPageIndex = Convert.ToInt32(PageIndex) + 1; break; case "Last": ViewBag.P2Index = PageCount; NowPageIndex = Convert.ToInt32(PageCount); break; } var MyTestPagesList = LzsDB.MyTestPages.OrderBy(a => a.Id); return View(MyTestPagesList.ToPagedList(NowPageIndex, 5)); }
分頁后的效果如下
我插入了120萬條數據,每頁顯示5條,在本機測試,分頁還是蠻快的。
整個源程序點此下載,本例子是vs2010,MVC3,配置好數據庫便可運行。