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