分页控件是为页面数据分页导航显示的一个可重用控件。分页控件一般需要指定页码(PageIndex)、总记录数据(RecordCount)、页记录数(PageSize),可自动计算出页码数(PageCount)显示出来。如果使用客户端分页应该还要计算分页数据,下面我从如下几个方面来说分页控件。
一、GET和POST分页方式
GET和POST分页不同之处,在于传递分页参数的方式。GET分页使用URL地址附加参数方式,而POST则是在提交表单中设置分页参数,可以在页面中存放hidden控件。在ASP.NET中可以使用Postback,使用ViewState保存分页参数。一般在前台页面列表都是用GET方式分页,这样在URL中就包含了分页信息,有利于SEO搜索引擎收录,个人推荐使用GET方式在URL地址分页。
二、服务端分页和客户端分页
这里所说的服务端和客户端分页是指在设置列表数据源的方式不同来划分的。对于存在大量数据的情况下一般都会使用服务端分页,即在服务器端获取已分页的数据显示,需要显示第几页数据就从数据库中获取第几页的数据,在数据库中使用分页函数完成分页返回数据。客户端分页是指一次返回所有记录,再在服务器端中自行分页,在ASP.NET中可以使用PagedDataSource对象来分页,在指定数据源和页码后可以自动计算页数和分页。客户端分页只适应于数据量不大的情况下的分页。
三、自定义分页控件和用户控件分页
1.自定义分页控件
将分页控件做成通用的ASP.NET组件首选考虑使用自定义控件,这样每个页面将控件拖放过来就可以用。下面是我网站列表显示的一个URL分页控件,支持服务端分页和客户端分页,支持自定义输入页码数和显示记录条数。自定义分页控件代码如下:
自定义分页控件
1using System;
2using System.Collections.Generic;
3using System.Text;
4
5using System.ComponentModel;
6using System.Web;
7using System.Web.UI;
8using System.Web.UI.WebControls;
9
10
11namespace Common.Control
12...{
13public class Pager : System.Web.UI.Control, System.Web.UI.INamingContainer
14...{
15
16private int pageSize = 20;
17
18[Description("页大小")]
19public int PageSize
20...{
21get ...{
22this.SetPage();
23return this.pageSize;
24}
25set ...{ pageSize = value; }
26}
27
28private int pageIndex = 1;
29
30[Description("页码")]
31public int PageIndex
32...{
33get ...{
34this.SetPage();
35return pageIndex;
36}
37set ...{ pageIndex = value; }
38}
39
40
41private bool isSetRecordCount = false;
42
43private int recordCount = 0;
44
45[Description("总记录数")]
46public int RecordCount
47...{
48get ...{ return this.recordCount; }
49set
50...{
51this.recordCount = value;
52this.isSetRecordCount = true;
53
54this.SetPage();
55}
56}
57
58private int pageCount = 0;
59
60[Description("总页数")]
61public int PageCount
62...{
63get ...{
64this.SetPage();
65return pageCount;
66}
67set ...{ pageCount = value; }
68}
69
70private int showPageCount = 10;
71
72[Description("显示的页码数")]
73public int ShowPageCount
74...{
75get ...{ return showPageCount; }
76set ...{ showPageCount = value; }
77}
78
79private string cssClass;
80
81[Description("样式类")]
82public string CssClass
83...{
84get ...{ return cssClass; }
85set ...{ cssClass = value; }
86}
87
88private string emptyData = "<div class=\"empty\">暂无数据</div>";
89
90[Description("空数据时候呈现的内容")]
91public string EmptyData
92...{
93get ...{ return emptyData; }
94set ...{ emptyData = value; }
95}
96
97private bool showDivContainer = true;
98
99[Description("显示包裹页码的DIV容器")]
100public bool ShowDivContainer
101...{
102get ...{ return showDivContainer; }
103set ...{ showDivContainer = value; }
104}
105
106private bool showPageGo = false;
107
108[Description("显示页面快速跳转表单")]
109public bool ShowPageGo
110...{
111get ...{ return showPageGo; }
112set
113...{
114this.showPageGo = value;
115if (this.showPageGo)
116this.savePageSize = true;
117}
118}
119
120private bool showFirstPage = true;
121
122[Description("显示第一页")]
123public bool ShowFirstPage
124...{
125get ...{ return showFirstPage; }
126set ...{ showFirstPage = value; }
127}
128
129private bool showLastPage = true;
130
131[Description("显示最后一页")]
132public bool ShowLastPage
133...{
134get ...{ return showLastPage; }
135set ...{ showLastPage = value; }
136}
137
138private string pageKey = "page";
139
140[Description("页码查询字符串的Key")]
141public string PageKey
142...{
143get ...{ return pageKey; }
144set ...{ pageKey = value; }
145}
146
147private string pageSizeKey = "pagesize";
148
149[Description("显示记录数查询字符串的Key")]
150public string PageSizeKey
151...{
152get ...{ return pageSizeKey; }
153set ...{ pageSizeKey = value; }
154}
155
156private bool savePageSize = false;
157
158[Description("自动保存显示行数")]
159public bool SavePageSize
160...{
161get ...{ return savePageSize; }
162set ...{ savePageSize = value; }
163}
164
165private bool saveQuery = true;
166
167[Description("自动保存页面查询字符串")]
168public bool SaveQuery
169...{
170get ...{ return saveQuery; }
171set ...{ saveQuery = value; }
172}
173
174private bool rawUrl = false;
175
176[Description("使用原始URL路径")]
177public bool RawUrl
178...{
179get ...{ return rawUrl; }
180set ...{ rawUrl = value; }
181}
182
183private string removeKey;
184
185[Description("移除的字符串Keys")]
186public string RemoveKey
187...{
188get ...{ return removeKey; }
189set ...{ removeKey = value; }
190}
191
192private void SetPage()
193...{
194if (Context == null) return;
195
196int pageindex = 1, pagesize = 20;
197if (int.TryParse(Context.Request.QueryString[this.pageKey], out pageindex))
198...{
199this.pageIndex = pageindex;
200}
201if (int.TryParse(Context.Request.QueryString[this.pageSizeKey], out pagesize) && pagesize > 0)
202...{
203this.pageSize = pagesize;
204}
205
206this.pageCount = (int)Math.Ceiling(this.recordCount * 1.0 / this.pageSize);
207
208if (this.pageIndex < 1)
209this.pageIndex = 1;
210if (this.pageIndex > this.pageCount && this.pageCount != 0)
211this.pageIndex = this.pageCount;
212}
213
214/**//// <summary>
215/// 设置分页的数据源,返回使用PagedDataSource客户端分页后的数据
216/// </summary>
217public PagedDataSource SetDataSource(System.Collections.IList dataSource)
218...{
219if (dataSource == null) return null;
220
221this.SetPage();
222this.RecordCount = dataSource.Count;
223
224PagedDataSource pds = new PagedDataSource();
225pds.DataSource = dataSource;
226pds.AllowPaging = true;
227pds.CurrentPageIndex = this.pageIndex - 1;
228pds.PageSize = this.pageSize;
229
230return pds;
231![]()
232}
233
234protected override void Render(HtmlTextWriter writer)
235...{
236
237if (Context == null)
238...{
239writer.WriteLine("Pager");
240return;
241}
242
243this.SetPage();
244
245System.Text.StringBuilder sb = new System.Text.StringBuilder();
246
247if (Context.Items.Contains("CurrentPath"))
248...{
249sb.Append(Context.Items["CurrentPath"].ToString());
250}
251else if (this.rawUrl)
252...{
253sb.Append(Context.Request.RawUrl.IndexOf("?") == -1 ? Context.Request.RawUrl : Context.Request.RawUrl.Substring(0, Context.Request.RawUrl.IndexOf("?")));
254}
255else
256...{
257sb.Append(Context.Request.Path);
258}
259sb.Append("?");
260
261if (this.savePageSize)
262...{
263sb.AppendFormat("{0}={1}&", this.pageSizeKey, this.pageSize.ToString());
264}
265
266if (this.saveQuery)
267...{
268for (int i = 0; i < Context.Request.QueryString.Count; i++)
269...{
270if (HttpContext.Current.Request.QueryString.Keys[i] != null
271&& HttpContext.Current.Request.QueryString.Keys[i].ToLower() != this.pageSizeKey.ToLower()
272&& HttpContext.Current.Request.QueryString.Keys[i].ToLower() != this.pageKey.ToLower()
273&& !("," + this.removeKey + ",").Contains("," + HttpContext.Current.Request.QueryString.Keys[i] + ","))
274sb.AppendFormat("{0}={1}&", HttpContext.Current.Request.QueryString.Keys[i], HttpContext.Current.Request.QueryString[i]);
275}
276}
277sb.AppendFormat("{0}=", pageKey);
278
279
280if (this.recordCount <= 0) ...{
281if (this.isSetRecordCount) ...{
282writer.WriteLine(this.emptyData);
283}
284return;
285}
286
287if (this.showDivContainer)
288...{
289writer.WriteLine("<div class=\"" + (string.IsNullOrEmpty(this.cssClass) ? "pagination" : this.cssClass) + "\" id=\"" + this.ClientID + "\">");
290}
291
292if (this.showFirstPage && pageIndex > 1)
293...{
294//if (pageIndex <= 1) {
295// writer.Write("<span class=\"disabled\"><<</span><span class=\"disabled\"><</span>");
296//}
297//else{
298writer.Write("<a title=\"第一页\" href=\"" + sb.ToString() + 1 + "\"><<</a>");
299writer.Write("<a title=\"上一页\" href=\"" + sb.ToString() + (pageIndex - 1).ToString() + "\"><</a>");
300//}
301}
302
303int startPage = this.pageIndex - this.showPageCount / 2;
304int endPage = this.pageIndex + (this.showPageCount - 1) / 2;
305if (startPage < 1)
306...{
307endPage += 1 - startPage;
308startPage = 1;
309}
310if (endPage > this.pageCount)
311...{
312startPage -= endPage - this.pageCount;
313if (startPage < 1) startPage = 1;
314endPage = this.pageCount;
315}
316
317if (this.pageCount > 1)
318...{
319for (int i = startPage; i <= endPage; i++)
320...{
321if (i == pageIndex)
322writer.Write("<span class=\"current\">" + i + "</span>");
323else
324writer.Write("<a title=\"第" + i + "页\" href=\"" + sb.ToString() + i.ToString() + "\">" + i + "</a>");
325}
326}
327
328if (this.showLastPage && pageIndex < pageCount)
329...{
330//if (pageIndex >= pageCount) {
331// writer.Write("<span class=\"disabled\">></span><span class=\"disabled\">>></span>");
332//}
333//else {
334writer.Write("<a title=\"下一页\" href=\"" + sb.ToString() + (pageIndex + 1).ToString() + "\">></a>");
335writer.Write("<a title=\"最后一页\" href=\"" + sb.ToString() + this.pageCount + "\">>></a>");
336//}
337}
338
339if (this.ShowPageGo)
340...{
341string locationRedirect = "location='" + sb.ToString() + "'+this.previousSibling.value;";
342if (this.savePageSize)
343...{
344locationRedirect = "location='" + sb.ToString().Replace(this.pageSizeKey + "=" + this.pageSize.ToString() + "&", this.pageSizeKey + "='+this.previousSibling.previousSibling.previousSibling.value+'&") + "'+this.previousSibling.value;";
345}
346
347writer.WriteLine();
348writer.Write("<form method=\"get\" action=\"" + sb.ToString() + this.pageIndex.ToString() + "\">");
349writer.Write("<span class=\"page\" onkeypress=\"return function (e){e=window.event||e;var num=e.which?e.which:e.keyCode;if(num==13){this.lastChild.onclick();return false;}}\">显示行:<input type=\"text\" name=\"" + this.pageSizeKey + "\" title=\"输入按回车跳转\" size=\"4\" value=\"" + this.pageSize + "\" class=\"text\" />/" + this.recordCount + ",跳转:<input type=\"text\" name=\"" + this.pageKey + "\" title=\"输入按回车跳转\" size=\"4\" value=\"" + this.pageIndex + "\" class=\"text\" /><input type=\"submit\" class=\"btn\" onclick=\"" + locationRedirect + "return false;\" value=\"Go\" /></span>");
350writer.WriteLine("</form>");
351
352}
353
354if (this.showDivContainer)
355...{
356writer.Write("</div>");
357}
358
359}
360
361}
362
363}
2.用户控件分页
分页控件同样可以做成ASCX用户控件,这样在每个页面注册控件,和自定义控件使用差不多。下面是一个使用Post方式的分页用户控件,使用了分页事件、视图状态等,代码如下:
Pager.ascx
1<%...@ Control Language="C#" AutoEventWireup="true" CodeBehind="Pager.ascx.cs" Inherits="Common.Inc.Pager" %>
2
3<table width="100%">
4<tr>
5<td align="right">
6![]()
7<asp:Label ID="Labeldata" runat="server" ForeColor="Red"></asp:Label>
8![]()
9<asp:Label ID="lblRecordCount" runat="server" Text="记录数"></asp:Label>
10![]()
11
12![]()
13<asp:LinkButton ID="lnkbtnFirst" CommandName="First" runat="server" OnClick="PagerButtonClick">首页</asp:LinkButton>
14<asp:LinkButton ID="lnkbtnPrev" CommandName="Pre" runat="server" OnClick="PagerButtonClick">上一页</asp:LinkButton>
15<asp:LinkButton ID="lnkbtnNext" CommandName="Next" runat="server" OnClick="PagerButtonClick">下一页</asp:LinkButton>
16<asp:LinkButton ID="lnkbtnLast" CommandName="Last" runat="server" OnClick="PagerButtonClick">尾页</asp:LinkButton>
17
18<asp:TextBox ID="txtJumpPage" runat="server" Text="1" Width="38px" ValidationGroup="vgSkip" />
19<asp:RequiredFieldValidator ID="RequiredFieldValidator1" runat="server" ControlToValidate="txtJumpPage"
20Display="Dynamic" ErrorMessage="请输入跳转的页数!" ValidationGroup="vgSkip"></asp:RequiredFieldValidator>
21<asp:RegularExpressionValidator ID="RegularExpressionValidator1" runat="server" ControlToValidate="txtJumpPage"
22Display="Dynamic" ErrorMessage="页数只能为正数!" ValidationExpression="\d*" ValidationGroup="vgSkip"></asp:RegularExpressionValidator>
23<asp:LinkButton ID="lnkbtnJumpPage" runat="server" OnClick="lnkbtnJumpPage_Click" ValidationGroup="vgSkip">跳转</asp:LinkButton>
24![]()
25</td>
26</tr>
27</table>
Pager.ascx.cs
1using System;
2using System.Collections.Generic;
3using System.Linq;
4using System.Web;
5using System.Web.UI;
6using System.Web.UI.WebControls;
7using System.Collections;
8
9namespace Common.Inc
10...{
11
12
13public partial class Pager : System.Web.UI.UserControl
14...{
15
16private string emptyDataText = "暂时没有数据!";
17public string EmptyDataText
18...{
19get ...{ return emptyDataText; }
20set ...{ emptyDataText = value; }
21}
22
23private int pageSize = 10;
24public int PageSize
25...{
26get ...{ return pageSize; }
27set ...{ pageSize = value; }
28}
29
30private int recordCount = -1;
31public int RecordCount
32...{
33get ...{ return recordCount; }
34set
35...{
36recordCount = value;
37RenderPager();
38}
39}
40
41public int PageIndex
42...{
43get
44...{
45string stateBagName = "PageIndex" + this.UniqueID;
46if (ViewState[stateBagName] == null)
47return 0;
48else
49return int.Parse(ViewState[stateBagName].ToString());
50}
51set
52...{
53string stateBagName = "PageIndex" + this.UniqueID;
54ViewState[stateBagName] = value.ToString();
55}
56}
57
58public int PageCount
59...{
60get
61...{
62string stateBagName = "PageCount" + this.UniqueID;
63if (ViewState[stateBagName] == null)
64return 0;
65else
66return int.Parse(ViewState[stateBagName].ToString());
67}
68set
69...{
70string stateBagName = "PageCount" + this.UniqueID;
71ViewState[stateBagName] = value.ToString();
72}
73}
74
75![]()
76
77//
78// 摘要:
79// 在单击某一页导航按钮时发生。
80public event PagerEventHandler PageIndexChanging;
81
82/**//// <summary>
83/// 分页对象
84/// </summary>
85public PagedDataSource PagerDataSource;
86
87
88public PagedDataSource SetPager(IEnumerable source)
89...{
90PagerDataSource = new PagedDataSource();
91![]()
92PagerDataSource.AllowPaging = true;
93
94PagerDataSource.DataSource = source;
95PagerDataSource.PageSize = PageSize;
96PagerDataSource.CurrentPageIndex = PageIndex;
97
98this.RecordCount = PagerDataSource.DataSourceCount;
99![]()
100return PagerDataSource;
101}
102
103
104/**//// <summary>
105/// 分页的相关参数设置
106/// </summary>
107protected void RenderPager()
108...{
109this.PageCount = (int)Math.Ceiling(RecordCount * 1.0 / PageSize);
110
111bool resetPageIndex = false;
112if (PageIndex < 0)
113...{
114this.PageIndex = 0;
115resetPageIndex = true;
116}
117if (PageIndex >= PageCount && PageCount>0)
118...{
119this.PageIndex = PageCount - 1;
120resetPageIndex = true;
121}
122if (PagerDataSource != null && resetPageIndex == true)
123...{
124PagerDataSource.CurrentPageIndex = PageIndex;
125}
126
127lnkbtnFirst.Visible = PageCount > 1;
128lnkbtnPrev.Visible = PageCount > 1;
129lnkbtnNext.Visible = PageCount > 1;
130lnkbtnLast.Visible = PageCount > 1;
131
132lnkbtnJumpPage.Visible = PageCount > 1;
133
134txtJumpPage.Visible = PageCount > 1;
135txtJumpPage.Text = (PageIndex + 1).ToString();
136![]()
137lblRecordCount.Text = "记录数" + RecordCount.ToString() + " 条";
138lblRecordCount.Visible = RecordCount > 0;
139Labeldata.Text = RecordCount > 0 ? string.Empty : EmptyDataText;
140
141lnkbtnFirst.Enabled = lnkbtnPrev.Enabled = PageIndex > 0;
142lnkbtnNext.Enabled = lnkbtnLast.Enabled = PageIndex < PageCount - 1;
143![]()
144}
145
146
147/**//// <summary>
148/// 跳转到指定页面,页面参数由输入控件获取
149/// </summary>
150/// <param name="sender"></param>
151/// <param name="e"></param>
152protected void lnkbtnJumpPage_Click(object sender, EventArgs e)
153...{
154
155int newPageIndex = int.Parse(txtJumpPage.Text) - 1;
156
157OnPageIndexChanging(new PagerEventArgs(newPageIndex));
158}
159
160
161/**//// <summary>
162/// 首页,上一页,下一页,尾页公用的点击程序
163/// </summary>
164/// <param name="sender"></param>
165/// <param name="e"></param>
166protected void PagerButtonClick(object sender, EventArgs e)
167...{
168int newPageIndex = 0;
169string commandName = ((LinkButton)sender).CommandName;
170switch(commandName)
171...{
172case "First":
173newPageIndex=0;
174break;
175case "Pre":
176newPageIndex = PageIndex-1;
177break;
178case "Next":
179newPageIndex = PageIndex+1;
180break;
181case "Last":
182newPageIndex = PageCount - 1;
183break;
184}
185
186OnPageIndexChanging(new PagerEventArgs(newPageIndex));
187
188}
189
190protected virtual void OnPageIndexChanging(PagerEventArgs e)
191...{
192if (this.PageIndexChanging == null)
193throw new HttpException("Pager“" + ID + "”激发了未处理的事件“PageIndexChanging”。 ");
194![]()
195this.PageIndexChanging(this, e);
196}
197
198
199}
200
201![]()
202public delegate void PagerEventHandler(object sender, PagerEventArgs e);
203
204public class PagerEventArgs : System.ComponentModel.CancelEventArgs
205...{
206
207public PagerEventArgs(int newPageIndex)
208...{
209this.NewPageIndex = newPageIndex;
210}
211
212public int NewPageIndex ...{ get; set; }
213}
214
215
216}
ASP.NET分页控件使用请参见:在线分页控件使用示例