前段时间的项目中需要使用到分页控件,在网上找了不少,最终还是自己动手写一个,比较简单,后续功能以后再实现,现把代码及思路写下来,望大家批评指正。分页控件的分页形式大多分三种,一种是用URL传值,通过给页面指定QueryString传值当前页的索引;另一种类似于GridView里面的分页方式,通过改变内部的PageIndex分页;还有一种是两种方式都包含,那样功能比较强大,在此不做评论。用URL传值的方式,相当于每点击分页按钮,页面就跳转至一个新的页面,那么页面IsPostBack值每次都是False,如果页面上不需要输入查询条件,那当然是没有问题的,如果查询页面上面要输入一些查询条件,自然用URL传值就不太适用了,至少你得把你输入的查询条件传递到新的URL中。故此,我在做这个控件时用到了用PageIndex传值的方式。首先我用了一个分页的存储过程,代码如下:
1create procedure sp_PageList
2@sqlstr nvarchar(4000), --查询字符串
3@currentpage int, --第N页
4@pagesize int --每页行数
5
6as
7set nocount on
8declare @P1 int, --P1是游标的id
9 @rowcount int
10exec sp_cursoropen @P1 output,@sqlstr,@scrollopt=1,@ccopt=1,@rowcount=@rowcount output
11set @currentpage=(@currentpage-1)*@pagesize+1
12exec sp_cursorfetch @P1,16,@currentpage,@pagesize
13exec sp_cursorclose @P1
14select @rowcount
15set nocount off
16
17GO
18
这个存储过程的执行结果包括三个表,第一个为空表,第二个是查询的结果集,显示的行数为@pagesize设置的大小,第三个是总记录数
下面是分页控件的代码:
1using System;
2using System.ComponentModel;
3using System.Text;
4using System.Web;
5using System.Web.UI;
6using System.Web.UI.WebControls;
7
8namespace WebControlEx
9{
10 [ToolboxData("<{0}:Pager runat=\"server\" >{0}:Pager>")]
11 public class Pager : CompositeControl, INamingContainer
12 {
13 公共属性#region 公共属性
14
15 [Browsable(true), Category("分页"), DefaultValue("0"), Localizable(true), Description("当前页的索引")]
16 public int PageIndex
17 {
18 get
19 {
20 return ViewState["PageIndex"] == null ? 0 : (int)ViewState["PageIndex"];
21 }
22
23 set
24 {
25 ViewState["PageIndex"] = value;
26 }
27 }
28
29 [Browsable(true), Category("分页"), DefaultValue("10"), Localizable(true), Description("数据源中每页要显示的行的数目")]
30 public int PageSize
31 {
32 get
33 {
34 return ViewState["PageSize"] == null ? 10 : (int)ViewState["PageSize"];
35 }
36
37 set
38 {
39 ViewState["PageSize"] = value;
40 }
41 }
42
43 [Browsable(true), Category("分页"), PersistenceMode(PersistenceMode.InnerProperty), Description("控制与控件关联的分页UI设置"), DesignerSerializationVisibility(DesignerSerializationVisibility.Content), NotifyParentProperty(true)]
44 public virtual PagerSettings PagerSettings
45 {
46 get
47 {
48 if (this._pagerSettings == null)
49 {
50 this._pagerSettings = new PagerSettings();
51 }
52 return this._pagerSettings;
53 }
54 }
55
56 [Browsable(true), Category("数据"), DefaultValue("0"), Localizable(true), Description("数据源的总行数")]
57 public int RecordCount
58 {
59 get
60 {
61 return ViewState["RecordCount"] == null ? 0 : (int)ViewState["RecordCount"];
62 }
63
64 set
65 {
66 ViewState["RecordCount"] = value;
67 }
68 }
69
70 #endregion
71
72 私有属性#region 私有属性
73
74 private int PageCount
75 {
76 get
77 {
78 if (this.RecordCount == 0 || this.PageSize == 0)
79 return 0;
80 return (int)Math.Ceiling(this.RecordCount / (this.PageSize * 1.0));
81 }
82 }
83
84 #endregion
85
86 私有变量#region 私有变量
87
88 private static readonly object EventPageIndexChanged = new object();
89 private PagerSettings _pagerSettings = new PagerSettings();
90
91 private LinkButton _lbtnFirst = new LinkButton();
92 private LinkButton _lbtnPrev = new LinkButton();
93 private LinkButton _lbtnNext = new LinkButton();
94 private LinkButton _lbtnLast = new LinkButton();
95
96 private TextBox txtPageIndex = new TextBox();
97
98 #endregion
99
100 事件相关#region 事件相关
101
102 [Description("Pager_OnPageIndexChanged"), Category("Action")]
103 public event EventHandler PageIndexChanged
104 {
105 add
106 {
107 base.Events.AddHandler(EventPageIndexChanged, value);
108 }
109 remove
110 {
111 base.Events.RemoveHandler(EventPageIndexChanged, value);
112 }
113 }
114
115 protected void OnPageChanged(EventArgs e)
116 {
117 EventHandler handler = (EventHandler)Events[EventPageIndexChanged];
118 if (handler != null)
119 {
120 handler(this, e);
121 }
122 }
123
124 #endregion
125
126 重写基类方法#region 重写基类方法
127
128 protected override void CreateChildControls()
129 {
130 this.Controls.Clear();
131
132 this._lbtnFirst.Text = this._pagerSettings.FirstPageText;
133 this._lbtnFirst.CommandName = "First";
134 this._lbtnFirst.Click += new EventHandler(LinkButtion_Click);
135
136 this._lbtnPrev.Text = this._pagerSettings.PreviousPageText;
137 this._lbtnPrev.CommandName = "Prev";
138 this._lbtnPrev.Click += new EventHandler(LinkButtion_Click);
139
140 this._lbtnNext.Text = this._pagerSettings.NextPageText;
141 this._lbtnNext.CommandName = "Next";
142 this._lbtnNext.Click += new EventHandler(LinkButtion_Click);
143
144 this._lbtnLast.Text = this._pagerSettings.LastPageText;
145 this._lbtnLast.CommandName = "Last";
146 this._lbtnLast.Click += new EventHandler(LinkButtion_Click);
147
148 txtPageIndex.Width = 30;
149 txtPageIndex.AutoPostBack = true;
150 txtPageIndex.TextChanged += new EventHandler(PageIndex_TextChanged);
151
152 this.Controls.Add(this._lbtnFirst);
153 this.Controls.Add(this._lbtnPrev);
154 this.Controls.Add(this._lbtnNext);
155 this.Controls.Add(this._lbtnLast);
156 this.Controls.Add(txtPageIndex);
157
158 base.CreateChildControls();
159 }
160
161 protected override void Render(HtmlTextWriter writer)
162 {
163 if (this.PageCount == 1)
164 return;
165 if (this.CssClass != "")
166 writer.Write("
167 else
168 writer.Write("
169 if (this.RecordCount == 0)
170 {
171 writer.Write("对不起,没有查询到相关记录!
172 return;
173 }
174 writer.Write("
总记录:{0}条,每页{1}条,当前页:{2}/{3} | ", this.RecordCount, this.PageSize, this.PageIndex + 1, this.PageCount);"); 179 if (this.PageIndex == 0 || this.PageCount == 1) 180 { 181 _lbtnFirst.Visible = false; 182 _lbtnPrev.Visible = false; 183 } 184 _lbtnFirst.RenderControl(writer); 185 writer.Write(" | "); 186 _lbtnPrev.RenderControl(writer); 187 writer.Write(" | ");"); 194 if (this.PageIndex == this.PageCount - 1 || this.PageCount == 1) 195 { 196 _lbtnNext.Visible = false; 197 _lbtnLast.Visible = false; 198 } 199 _lbtnNext.RenderControl(writer); 200 writer.Write(" | "); 201 _lbtnLast.RenderControl(writer); 202 writer.Write(" | ");跳转至: | "width:45px\">"); 209 txtPageIndex.RenderControl(writer); 210 writer.Write(" |
211
212 #endregion
213 }
214
215 #endregion
216
217 子控件的方法#region 子控件的方法
218
219 private void LinkButtion_Click(object sender, EventArgs e)
220 {
221 string commandName = (sender as LinkButton).CommandName;
222 switch (commandName)
223 {
224 case "First": this.PageIndex = 0; break;
225 case "Prev": this.PageIndex--; break;
226 case "Next": this.PageIndex++; break;
227 case "Last": this.PageIndex = this.PageCount - 1; break;
228 }
229 OnPageChanged(e);
230 }
231
232 private void PageIndex_TextChanged(object sender, EventArgs e)
233 {
234 if (txtPageIndex.Text.Trim().Length == 0)
235 return;
236 int pageIndex = 0;
237 if (int.TryParse(txtPageIndex.Text, out pageIndex))
238 {
239 if (pageIndex < 1)
240 this.PageIndex = 0;
241 else if (pageIndex > this.PageCount)
242 this.PageIndex = this.PageCount - 1;
243 else
244 this.PageIndex = pageIndex - 1;
245 }
246 OnPageChanged(e);
247 }
248
249 #endregion
250 }
251}
252
代码不用多解释,当页数为1时,无任何输出,记录为零时,显示无相关记录的提示,其它情况下输出一个Div 和一个Table,Div是为了样式控制方便而输出的。
下面是用C#代码调用上面分页存储过程的示例
///
/// 数据分页
///
/// Sql语句
/// 当前为第几页
/// 每页行数
/// 返回的总页数
/// 返回的总记录数
///
private DataTable PagerList(string cmdText, int curPage, int pageSize, out int rowCount)
{
SqlConnection con = new SqlConnection("server=.;database=dbname;user id=user;password=password");
DataSet ds = new DataSet();
SqlDataAdapter da = new SqlDataAdapter("sp_PageList", con);
da.SelectCommand.CommandType = CommandType.StoredProcedure;
SqlParameter[] paras = new SqlParameter[]
{
new SqlParameter("@sqlstr",SqlDbType.NVarChar,4000),
new SqlParameter("@currentpage",SqlDbType.Int),
new SqlParameter("@pagesize",SqlDbType.Int)
};
paras[0].Value = cmdText;
paras[1].Value = curPage;
paras[2].Value = pageSize;
foreach (SqlParameter para in paras)
{
da.SelectCommand.Parameters.Add(para);
}
try
{
con.Open();
da.Fill(ds);
con.Close();
}
catch(Exception ex)
{
throw new Exception(ex.Message);
}
rowCount = Convert.ToInt32(ds.Tables[2].Rows[0][0]);
return ds.Tables[1];
}
public DataTable GetLog(int curPage, int pageSize, out int rowCount)
{
return this.PagerList("select *from tb_Log",curPage,pageSize,out rowCount);
}
之后便是将控件拖到页面上,设置PageSize值 绑定数据表到数据控件上
public void BindGrid()
{
int recordCount =0;
GridView1.DataSource = this.GetLog(Pager1.PageIndex + 1, Pager1.PageSize,out recordCount);
GridView1.DataBind();
Pager1.RecordCount = recordCount;
}
///
/// 分页控件的分页事件
///
///
///
protected void Pager1_PageIndexChanged(object sender, EventArgs e)
{
this.BindGrid();
}
至此,该控件从编码到测试就完成了,测试的代码需要大家根据实际环境去调正一下才能运行,总结一下,这个分页控件对数据源、数据绑定控件都不关心,它要做的是传递给数据源当前页的索引值,分页大小,然后接受数据源传递过来的总记录数,至于数据绑定控件,GridView,DataList,Repeater都可以使用这个分页控件。