对于一个大型业务系统来说,数据分页显示,是必不可少的。

但是怎么分、用什么分,方法和工具就有很多了。。。

刚入门的时候,总是会很习惯的从工具箱中拖出一个GridView,加上AllowPaging="true",再写个OnPageIndexChanging事件,OK,分页实现了。。。

发现这种方式效率差后,就开始拖.Net3.5中的独立分页控件了,忘了叫什么名字,公司用.Net2.0,没办法。

这些方式,基本上都是一次就查出所有数据,再分页。

------------------------------------------------------------------------------------------------------------------------------------------------

当然了,需要第几页就查第几页的数据,这才是最好的。 

所以,后来,也很傻的自己拖4个按钮(第一页、上一页、下一页、最后一页),一个下拉框(当前第N页),

然后为每个按钮写Click事件,为下拉框写Change事件,再配上分页存储过程,

嗯,是比之前几种方式要快一些。就是太繁琐,显然几乎没人会这么干。

 ------------------------------------------------------------------------------------------------------------------------------------------------

这会就有了做个简单的分页控件的想法,可是又不会,也没做过。

好吧,中关村买书去。。。

边看书边琢磨了两天,终于出来了。。。

不需要很强大,不需要很华丽,只要。。。够用就行。

 

加上CSS样式,最终显示效果就是这样,应该够用吧?反正我们是够了。。。哈哈


------------------------------------------------------------------------------------------------------------------------------------------------

首先,这是一个组合控件,5个按钮+1个输入框构成。

原理是让这5个按钮都调用同一个方法,同时再根据点击的按钮来判断页索引。

开始贴代码吧:

控件声明
 1 //设置控件在页面中的显示代码,如<Feli:Pager .....>
2 [assembly: TagPrefix("FeliControls", "Feli")]
3 namespace FeliControls
4 {
5 [DefaultProperty("ShowCountInfo")]//在VS属性栏中默认选中的属性
6 [DefaultEvent("PageIndexChanged")]//默认事件,设置后,双击控件就进入CS代码中该事件的声明,如Button控件的这个属性就是Click
7 [ToolboxData("<{0}:Pager runat=server></{0}:Pager>")]//在页面中调用时的显示代码
8 public class Pager : CompositeControl
9 {
10 //继承自CompositeControl,即组合控件
11 }
12 }


然后呢,就是各个子控件了。

子控件声明
1 private Button btnFirst;
2 private Button btnPrev;
3 private Button btnNext;
4 private Button btnLast;
5 private Button btnDiy;
6
7 private TextBox txtPageIndex;

接着呢,这些个按钮的文字,得允许自己设置吧。

子控件属性
  1         [Bindable(true)]
2 [Category("Appearance")]//在VS属性栏中所属的分组
3 [DefaultValue("")]
4 [Localizable(true)]
5 [Description("是否显示数据总数及当前显示数据信息")]//显示在VS属性栏下页的描述信息
6 public bool ShowCountInfo
7 {
8 get
9 {
10 bool s = true;
11 if(!this.DesignMode)//非设计模式才取ViewState
12 {
13 if (ViewState["ShowCountInfo"] != null)
14 {
15 s = (bool)ViewState["ShowCountInfo"];
16 }
17 }
18 return s;
19 }
20
21 set
22 {
23 ViewState["ShowCountInfo"] = value;
24 }
25 }
26 /// <summary>
27 /// 第一页按钮文字描述
28 /// </summary>
29 [Bindable(true)]
30 [Category("分页按钮属性")]
31 [DefaultValue("")]
32 [Localizable(true)]
33 [Description("第一页按钮文字")]
34 public string FirstPageText
35 {
36 get
37 {
38 EnsureChildControls();
39 return btnFirst.Text;
40 }
41
42 set
43 {
44 EnsureChildControls();
45 btnFirst.Text = value;
46 }
47 }
48 /// <summary>
49 /// 上一页按钮文字描述
50 /// </summary>
51 [Bindable(true)]
52 [Category("分页按钮属性")]
53 [DefaultValue("")]
54 [Localizable(true)]
55 [Description("上一页按钮文字")]
56 public string PrevPageText
57 {
58 get
59 {
60 EnsureChildControls();
61 return btnPrev.Text;
62 }
63
64 set
65 {
66 EnsureChildControls();
67 btnPrev.Text = value;
68 }
69 }
70 /// <summary>
71 /// 下一页按钮文字描述
72 /// </summary>
73 [Bindable(true)]
74 [Category("分页按钮属性")]
75 [DefaultValue("")]
76 [Localizable(true)]
77 [Description("下一页按钮文字")]
78 public string NextPageText
79 {
80 get
81 {
82 EnsureChildControls();
83 return btnNext.Text;
84 }
85
86 set
87 {
88 EnsureChildControls();
89 btnNext.Text = value;
90 }
91 }
92 /// <summary>
93 /// 最后一页按钮文字描述
94 /// </summary>
95 [Bindable(true)]
96 [Category("分页按钮属性")]
97 [DefaultValue("")]
98 [Localizable(true)]
99 [Description("最后一页按钮文字")]
100 public string LastPageText
101 {
102 get
103 {
104 EnsureChildControls();
105 return btnLast.Text;
106 }
107
108 set
109 {
110 EnsureChildControls();
111 btnLast.Text = value;
112 }
113 }
114
115 /// <summary>
116 /// GO按钮文字描述
117 /// </summary>
118 [Bindable(true)]
119 [Category("分页按钮属性")]
120 [DefaultValue("")]
121 [Localizable(true)]
122 [Description("自定义跳转到页面按钮文字")]
123 public string BtnGoText
124 {
125 get
126 {
127 EnsureChildControls();
128 return btnDiy.Text;
129 }
130
131 set
132 {
133 EnsureChildControls();
134 btnDiy.Text = value;
135 }
136 }

嗯,还有分页(第几页、数据总数、每页显示几条等)数量信息

分页属性相关
  1         public int CurrentPageIndex
2 {
3 get
4 {
5 int idx = 1;
6 if (!this.DesignMode)
7 {
8 if (txtPageIndex.Text != null && txtPageIndex.Text != "")
9 {
10 idx = Convert.ToInt32(txtPageIndex.Text.Trim());
11 }
12 }
13 return idx;
14 }
15 set
16 {
17 EnsureChildControls();//确认子控件已创建,未创建则会调用下面的CreateChildControls方法
18
19 if (value < 2)
20 {
21 value = 1;
22 }
23 if (value >= this.PageCount)
24 {
25 value = this.PageCount;
26 }
27 if (ViewState["CurrentPageIndex"] != null)
28 {
29 string strPage = ViewState["CurrentPageIndex"].ToString();
30 }
31 txtPageIndex.Text = value.ToString();
32 }
33 }
34 /// <summary>
35 /// 总页数
36 /// </summary>
37 public int PageCount
38 {
39 get
40 {
41 if (this.DesignMode)
42 {
43 return 0;
44 }
45 else
46 {
47 return RecordCount % PageSize == 0 ? RecordCount / PageSize : (RecordCount / PageSize) + 1;//直接计算共有多少页
48 }
49 }
50 }
51 /// <summary>
52 /// 每页显示的记录数
53 /// </summary>
54 [Bindable(true)]
55 [Category("分页信息")]
56 [DefaultValue("")]
57 [Localizable(true)]
58 [Description("每页显示的数据数")]
59 public int PageSize
60 {
61 get
62 {
63 int _size = 30;
64 if (!this.DesignMode)
65 {
66 if (ViewState["PageSize"] != null)
67 {
68 _size = (int)ViewState["PageSize"];
69 }
70 }
71 return _size;
72 }
73 set
74 {
75 ViewState["PageSize"] = value;
76 }
77 }
78
79 /// <summary>
80 /// 总记录数
81 /// </summary>
82 [Bindable(true)]
83 [Category("分页信息")]
84 [DefaultValue("")]
85 [Localizable(true)]
86 [Description("总记录数")]
87 public int RecordCount
88 {
89 get
90 {
91 int idx = 0;
92 if (!this.DesignMode)
93 {
94 if (ViewState["RecordCount"] != null)
95 {
96 idx = (int)ViewState["RecordCount"];
97 }
98 }
99 return idx;
100 }
101 set
102 {
103 ViewState["RecordCount"] = value;
104 }
105 }

因为自定义服务器控件,未重写HTML标签的话,好像都是<span>,所以就重写了下,用DIV

重写控件生成的HTML代码标签
 1         /// <summary>
2 /// 重写控件HTML代码开始标签
3 /// </summary>
4 protected override HtmlTextWriterTag TagKey
5 {
6 get
7 {
8 return HtmlTextWriterTag.Div;
9 }
10 }

接下来创建子控件了

创建子控件
 1         protected override void CreateChildControls()
2 {
3 this.Controls.Clear();//先清除现有的控件
4
5 btnFirst = new Button();
6 btnFirst.ID = "btnFirst";
7 btnFirst.CommandName = "Page";
8 btnFirst.CommandArgument = "ButtonFirst";
9 btnFirst.Click += new EventHandler(Change_PageIndex);//绑上单击事件
10 btnFirst.Text = "第一页";
11 btnFirst.CssClass = "input_border felipager_btn_first";
12
13 this.Controls.Add(btnFirst);
14
15 btnPrev = new Button();
16 btnPrev.ID = "btnPrev";
17 btnPrev.CommandName = "Page";
18 btnPrev.CommandArgument = "ButtonPrev";
19 btnPrev.Click += new EventHandler(Change_PageIndex);
20 btnPrev.Text = "上一页";
21 btnPrev.CssClass = "input_border mr20 felipager_btn_prev";
22
23 this.Controls.Add(btnPrev);
24
25 btnNext = new Button();
26 btnNext.ID = "btnNext";
27 btnNext.CommandName = "Page";
28 btnNext.CommandArgument = "ButtonNext";
29 btnNext.Click += new EventHandler(Change_PageIndex);
30 btnNext.Text = "下一页";
31 btnNext.CssClass = "input_border ml20 felipager_btn_next";
32
33 this.Controls.Add(btnNext);
34
35 btnLast = new Button();
36 btnLast.ID = "btnLast";
37 btnLast.CommandName = "Page";
38 btnLast.CommandArgument = "ButtonLast";
39 btnLast.Click += new EventHandler(Change_PageIndex);
40 btnLast.Text = "最后一页";
41 btnLast.CssClass = "input_border felipager_btn_last";
42
43 this.Controls.Add(btnLast);
44
45 btnDiy = new Button();
46 btnDiy.ID = "btnDiy";
47 btnDiy.CommandName = "Page";
48 btnDiy.CommandArgument = "ButtonDiy";
49 btnDiy.Click += new EventHandler(Change_PageIndex);
50 btnDiy.Text = "GO";
51 btnDiy.CssClass = "input_border felipager_btn_go";
52
53 this.Controls.Add(btnDiy);
54
55 txtPageIndex = new TextBox();
56 txtPageIndex.ID = "txtPageIndex";
57 txtPageIndex.Width = 30;
58 txtPageIndex.CssClass = "input_border felipager_txt_pageindex";
59
60 this.Controls.Add(txtPageIndex);
61
62 base.CreateChildControls();
63 }

可以看到,5个按钮都会触发同一事件。

各按钮单击事件
 1         void Change_PageIndex(object sender, EventArgs e)
2 {
3 //触发了点击事件,则将blnNoClick设为false.
4 blnNoClick = false;
5 Button btn = (Button)sender;
6 if (btn.CommandName == "Page")
7 {
8 PageChangedEventArgs ee = new PageChangedEventArgs();
9 if (btn.CommandArgument == "ButtonFirst")
10 {
11 this.CurrentPageIndex = 1;
12 }
13 if (btn.CommandArgument == "ButtonPrev")
14 {
15 this.CurrentPageIndex -= 1;
16 }
17 if (btn.CommandArgument == "ButtonNext")
18 {
19 this.CurrentPageIndex += 1;
20 }
21 if (btn.CommandArgument == "ButtonLast")
22 {
23 this.CurrentPageIndex = this.PageCount;
24 }
25 if (btn.CommandArgument == "ButtonDiy")
26 {
27 int intDiyIdx = 1;
28 //如果输入数字不合法,则跳转到第一页
29 if (int.TryParse(this.txtPageIndex.Text, out intDiyIdx))
30 {
31 if (intDiyIdx > 0)
32 {
33 this.CurrentPageIndex = intDiyIdx;
34 }
35 else
36 {
37 this.Page.RegisterStartupScript("tishi", "<script>alert('页索引必须为大于0的整数');</script>");
38 this.CurrentPageIndex = 1;
39 }
40 }
41 else
42 {
43 this.Page.RegisterStartupScript("tishi", "<script>alert('页索引必须为整数');</script>");
44 this.CurrentPageIndex = 1;
45 }
46 }
47 ee.CurrentPageIndex = this.CurrentPageIndex;
48 ee.PageCount = this.PageCount;
49 ee.PageSize = this.PageSize;
50 ee.RecordCount = this.RecordCount;
51 this.OnPageIndexChanged(ee);
52 }

最后就是渲染控件了

渲染控件
 1 protected override void RenderContents(HtmlTextWriter output)
2 {
3 output.AddAttribute(HtmlTextWriterAttribute.Class, "felipager_displayinfo");
4 output.RenderBeginTag(HtmlTextWriterTag.Div);
5 //如果需要显示数据总数信息,则显示
6 if (this.ShowCountInfo)
7 {
8 int intStart = this.PageSize * (this.CurrentPageIndex - 1);
9 if (intStart < 1)
10 {
11 intStart = 0;
12 }
13 int intEnd = this.PageSize * this.CurrentPageIndex;
14 if (intEnd > this.RecordCount)
15 {
16 intEnd = this.RecordCount;
17 }
18 intStart += 1;//每页的第一条的序号应该是1,而不是0
19 output.Write("共有 {0} 条数据,当前显示 {1} - {2} 条", this.RecordCount, intStart, intEnd);
20 }
21 output.RenderEndTag();
22
23 output.AddAttribute(HtmlTextWriterAttribute.Class, "felipager_navbox");
24 output.RenderBeginTag(HtmlTextWriterTag.Div);
25
26 #region ----控制导航按钮状态
27
28 //如果是第一页,则该按钮不可用
29 if (this.CurrentPageIndex == 1)
30 {
31 btnFirst.Enabled = false;
32 }
33 else
34 {
35 btnFirst.Enabled = true;
36 }
37 //如果是第一页,则该按钮不可用
38 if (this.CurrentPageIndex == 1)
39 {
40 btnPrev.Enabled = false;
41 }
42 else
43 {
44 btnPrev.Enabled = true;
45 }
46 //如果是最后一页,则该按钮不可用
47 if (this.CurrentPageIndex >= this.PageCount)
48 {
49 btnNext.Enabled = false;
50 }
51 else
52 {
53 btnNext.Enabled = true;
54 }
55 //如果是最后一页,则该按钮不可用
56 if (this.CurrentPageIndex >= this.PageCount)
57 {
58 btnLast.Enabled = false;
59 }
60 else
61 {
62 btnLast.Enabled = true;
63 }
64 //如果只有一页,则该按钮不可用
65 if (this.PageCount <= 1)
66 {
67 btnDiy.Enabled = false;
68 }
69 else
70 {
71 btnDiy.Enabled = true;
72 }
73 //如果只有一页,则该输入框不可用
74 if (this.PageCount <= 1)
75 {
76 txtPageIndex.Enabled = false;
77 }
78 else
79 {
80 txtPageIndex.Enabled = true;
81 }
82
83 #endregion
84
85 btnFirst.RenderControl(output);
86 btnPrev.RenderControl(output);
87 output.Write("当前第");
88 txtPageIndex.Text = this.CurrentPageIndex.ToString();
89 txtPageIndex.RenderControl(output);
90 btnDiy.RenderControl(output);
91 output.Write("页,共{0}页", this.PageCount);
92 btnNext.RenderControl(output);
93 btnLast.RenderControl(output);
94
95 output.RenderEndTag();
96 }

不过还缺了点东西,因为点击按钮时,分页控件需要将接下来要显示的页索引告诉分页方法,这样分页方法才知道需要去查询第几页的数据。

所以,我就写了这个。

分页控件事件参数
 1     /// <summary>
2 /// 分页控件事件参数类
3 /// </summary>
4 public class PageChangedEventArgs:System.EventArgs
5 {
6 public PageChangedEventArgs()
7 { }
8 /// <summary>
9 /// 当前页索引
10 /// </summary>
11 private int intCurrentPageIndex;
12 public new int CurrentPageIndex
13 {
14 get { return intCurrentPageIndex; }
15 set { intCurrentPageIndex = value; }
16 }
17 /// <summary>
18 /// 数据总页数
19 /// </summary>
20 private int intPageCount;
21 public new int PageCount
22 {
23 get { return intPageCount; }
24 set { intPageCount = value; }
25 }
26 /// <summary>
27 /// 每页显示的记录数
28 /// </summary>
29 private int intPageSize;
30 public new int PageSize
31 {
32 get { return intPageSize; }
33 set { intPageSize = value; }
34 }
35 /// <summary>
36 /// 数据总数
37 /// </summary>
38 private int intRecordCount;
39 public new int RecordCount
40 {
41 get { return intRecordCount; }
42 set { intRecordCount = value; }
43 }
44 }


------------------------------------------------------------------------------------------------------------------------------------------------

再来看看这控件怎么用吧

<Feli:Pager ID="fpgHistoryList" CssClass="felipager_main" runat="server" OnPageIndexChanged="fpgHistoryList_PageIndexChanged" /> 

当然,还需要设置每页显示的记录数及数据总数

this.fpgHistoryList.PageSize = 20;

this.fpgHistoryList.RecordCount = 600;

还有分页事件

分页事件
1     /// <summary>
2 /// 分页事件
3 /// </summary>
4 protected void fpgHistoryList_PageIndexChanged(object sender, FeliControls.PageChangedEventArgs e)
5 {
6 BindPagedData(e.CurrentPageIndex);
7 }

到这,就全部结束了。。。(各CSS样式,可根据需要自己定义)

点此下载全部代码

初学的成果,难免有不完善或错误的地方,若发现了,还请指出,不胜感激!!!

作者: 会动的稻草人 发表于 2011-07-21 15:33 原文链接

推荐.NET配套的通用数据层ORM框架:CYQ.Data 通用数据层框架
新浪微博粉丝精灵,刷粉丝、刷评论、刷转发、企业商家微博营销必备工具"