WinForm轻松实现自定义分页

转载至http://xuzhihong1987.blog.163.com/blog/static/267315872011315114240140/

以前都是做web开发,最近接触了下WinForm,发现WinForm分页控件好像都没有,网上搜索了一下,发现有很多网友写的分页控件,分页效果应该都能实现吧,只是其风格都不是很符合我想要的。做web的时候,我习惯了Extjs的Grid分页效果,所以也想在WinForm中做个类似的效果,所以咬咬牙,做个山寨版本的吧,虽然自己写费时费力,在项目进度考虑中不是很可取,但是还是特别想山寨一回,做自己喜欢的风格。

按照惯例,还是先看看实现效果图吧(有图有真像,才好继续下文呀)

应用效果:(效果有点难看,因为我是刚装的

xp系统,还是经典主题,如果换成Win7系统或其他主题,效果还是会很不错的)

 WinForm轻松实现自定义分页 _第1张图片

我们要做的就是上图显示的一个自定义控件,这个效果参考自我做

web开发使用的Extjs之Grid的分页效果(如下图)

 

Extjs的动画效果我们暂时就不实现了,这里只做个外观看起来想像即可,完全一样就脱离“山寨”概念了,总要比人家差点吧,谁让咱是模仿呢!

言归正传,我们现在就看看具体怎么实现吧:

 

第一步:先布局

    注:我们创建的是用户自定义控件,而不是WinForm窗体

WinForm轻松实现自定义分页 _第2张图片

就是先做出个显示效果,这个布局很简单,在这就不多说,重点就是“首页、前一页、后一页、末页”图标,每个图标分两种,一是能点击的高亮效果,一个是灰色不不能点击。以下是套图:(大家如果不喜欢,可以去做成自己喜欢的风格图片)

第二步:编写分页代码

   布局好了,那么第二步我们就要代码实现正确显示文字信息,分页事件,每页条数选择事件,公开属性和事件。以下是完整代码:

 

  1   /// <summary>
  2 
  3     /// 声明委托
  4 
  5     /// </summary>
  6 
  7     /// <param name="e"></param>
  8 
  9     public delegate void EventPagingHandler(EventArgs e);
 10 
 11  
 12 
 13     public partial class Paging : UserControl
 14 
 15     {
 16 
 17  
 18 
 19  
 20 
 21         public Paging()
 22 
 23         {
 24 
 25             InitializeComponent();
 26 
 27         }
 28 
 29  
 30 
 31         public event EventPagingHandler EventPaging;
 32 
 33  
 34 
 35         #region 公开属性
 36 
 37  
 38 
 39  
 40 
 41         private int _pageSize = 50;
 42 
 43         /// <summary>
 44 
 45         /// 每页显示记录数(默认50)
 46 
 47         /// </summary>
 48 
 49         public int PageSize
 50 
 51         {
 52 
 53             get
 54 
 55             {
 56 
 57                 return _pageSize;
 58 
 59             }
 60 
 61             set 
 62 
 63             {
 64 
 65                 if (value > 0)
 66 
 67                 {
 68 
 69                     _pageSize = value;
 70 
 71                 }
 72 
 73                 else
 74 
 75                 {
 76 
 77                     _pageSize = 50;
 78 
 79                 }
 80 
 81                 this.comboPageSize.Text = _pageSize.ToString();
 82 
 83             }
 84 
 85         }
 86 
 87         private int _currentPage = 1;
 88 
 89         /// <summary>
 90 
 91         /// 当前页
 92 
 93         /// </summary>
 94 
 95         public int CurrentPage
 96 
 97         {
 98 
 99             get 
100 
101             {
102 
103                 return _currentPage;
104 
105             }
106 
107             set 
108 
109             {
110 
111                 if (value > 0)
112 
113                 {
114 
115                     _currentPage = value;
116 
117                 }
118 
119                 else
120 
121                 {
122 
123                     _currentPage = 1;
124 
125                 }
126 
127                 
128 
129             }
130 
131         }
132 
133         private int _totalCount = 0;
134 
135         /// <summary>
136 
137         /// 总记录数
138 
139         /// </summary>
140 
141         public int TotalCount
142 
143         {
144 
145             get
146 
147             {
148 
149                 return _totalCount;
150 
151             }
152 
153             set 
154 
155             {
156 
157                 if (value>=0)
158 
159                 {
160 
161                     _totalCount = value;
162 
163                 } 
164 
165                 else
166 
167                 {
168 
169                     _totalCount = 0;
170 
171                 }
172 
173                 this.lblTotalCount.Text = this._totalCount.ToString();
174 
175                 CalculatePageCount();
176 
177                 this.lblRecordRegion.Text = GetRecordRegion();
178 
179             }
180 
181         }
182 
183  
184 
185         private int _pageCount = 0;
186 
187         /// <summary>
188 
189         /// 页数
190 
191         /// </summary>
192 
193         public int PageCount
194 
195         {
196 
197             get
198 
199             {
200 
201                 return _pageCount;
202 
203             }
204 
205             set 
206 
207             {
208 
209                 if (value>=0)
210 
211                 {
212 
213                     _pageCount = value;
214 
215                 } 
216 
217                 else
218 
219                 {
220 
221                     _pageCount = 0;
222 
223                 }
224 
225                 this.lblPageCount.Text = _pageCount + "";
226 
227             }
228 
229         }
230 
231  
232 
233        #endregion
234 
235  
236 
237         /// <summary>
238 
239         /// 计算页数
240 
241         /// </summary>
242 
243         private void CalculatePageCount()
244 
245         {
246 
247             if (this.TotalCount>0)
248 
249             {
250 
251                 this.PageCount = Convert.ToInt32(Math.Ceiling(Convert.ToDouble(this.TotalCount) / Convert.ToDouble(this.PageSize)));
252 
253             }
254 
255             else
256 
257             {
258 
259                 this.PageCount = 0;
260 
261             }
262 
263         }
264 
265  
266 
267         /// <summary>
268 
269         /// 获取显示记录区间(格式如:1-50)
270 
271         /// </summary>
272 
273         /// <returns></returns>
274 
275         private string GetRecordRegion()
276 
277         {
278 
279             if (this.PageCount == 1) //只有一页
280 
281             {
282 
283                 return "1-" + this.TotalCount.ToString();
284 
285             }
286 
287             else  //有多页
288 
289             {
290 
291                 if(this.CurrentPage==1) //当前显示为第一页
292 
293                 {
294 
295                     return "1-"+this.PageSize;
296 
297                 }
298 
299                 else if(this.CurrentPage==this.PageCount) //当前显示为最后一页
300 
301                 {
302 
303                     return ((this.CurrentPage-1)*this.PageSize+1) +"-"+this.TotalCount;
304 
305                 }
306 
307                 else //中间页
308 
309                 {
310 
311                     return ((this.CurrentPage-1) * this.PageSize+1)   + "-" + this.CurrentPage  * this.PageSize;
312 
313                 }
314 
315               
316             }
317 
318         }
319 
320  
321 
322  
323 
324         /// <summary>
325 
326         /// 数据绑定
327 
328         /// </summary>
329 
330         public void Bind()
331 
332         {
333 
334             if (this.EventPaging != null)
335 
336             {
337 
338                 this.EventPaging(new EventArgs());
339 
340             }
341 
342             if (this.CurrentPage>this.PageCount)
343 
344             {
345 
346                 this.CurrentPage = this.PageCount;
347 
348             }
349 
350             this.txtBoxCurPage.Text = this.CurrentPage+"";
351 
352             this.lblTotalCount.Text = this.TotalCount+"";
353 
354             this.lblPageCount.Text = this.PageCount+"";
355 
356             this.lblRecordRegion.Text = GetRecordRegion();
357 
358             if (this.CurrentPage==1)
359 
360             {
361 
362                 this.btnFirst.Enabled = false;
363 
364                 this.btnPrev.Enabled = false;
365 
366                 this.btnFirst.Image = global::CHVM.Properties.Resources.page_first_disabled;
367 
368                 this.btnPrev.Image = global::CHVM.Properties.Resources.page_prev_disabled;
369 
370             }
371 
372             else
373 
374             {
375 
376                 this.btnFirst.Enabled = true;
377 
378                 this.btnPrev.Enabled = true;
379 
380                 this.btnFirst.Image = global::CHVM.Properties.Resources.page_first;
381 
382                 this.btnPrev.Image = global::CHVM.Properties.Resources.page_prev;
383 
384             }
385 
386             if (this.CurrentPage == this.PageCount)
387 
388             {
389 
390                 this.btnNext.Enabled = false;
391 
392                 this.btnLast.Enabled = false;
393 
394                 this.btnNext.Image = global::CHVM.Properties.Resources.page_next_disabled;
395 
396                 this.btnLast.Image = global::CHVM.Properties.Resources.page_last_disabled;
397 
398             } 
399 
400             else
401 
402             {
403 
404                 this.btnNext.Enabled = true;
405 
406                 this.btnLast.Enabled = true;
407 
408                 this.btnNext.Image = global::CHVM.Properties.Resources.page_next;
409 
410                 this.btnLast.Image = global::CHVM.Properties.Resources.page_last;
411 
412             }
413 
414             if (this.TotalCount==0)
415 
416             {
417 
418                 this.btnFirst.Enabled = false;
419 
420                 this.btnPrev.Enabled = false;
421 
422                 this.btnNext.Enabled = false;
423 
424                 this.btnLast.Enabled = false;
425 
426                 this.btnFirst.Image = global::CHVM.Properties.Resources.page_first_disabled;
427 
428                 this.btnPrev.Image = global::CHVM.Properties.Resources.page_prev_disabled;
429 
430                 this.btnNext.Image = global::CHVM.Properties.Resources.page_next_disabled;
431 
432                 this.btnLast.Image = global::CHVM.Properties.Resources.page_last_disabled;
433 
434             }
435 
436  
437 
438         }
439 
440  
441 
442         private void btnFirst_Click(object sender, EventArgs e)
443 
444         {
445 
446             this.CurrentPage = 1;
447 
448             this.Bind();
449 
450         }
451 
452  
453 
454         private void btnPrev_Click(object sender, EventArgs e)
455 
456         {
457 
458             this.CurrentPage -= 1;            
459 
460             this.Bind();
461 
462         }
463 
464  
465 
466         private void btnNext_Click(object sender, EventArgs e)
467 
468         {
469 
470             this.CurrentPage += 1;
471 
472             this.Bind();
473 
474         }
475 
476  
477 
478         private void btnLast_Click(object sender, EventArgs e)
479 
480         {
481 
482             this.CurrentPage = this.PageCount;
483 
484             this.Bind();
485 
486         }
487 
488  
489 
490         /// <summary>
491 
492         ///  改变每页条数
493 
494         /// </summary>
495 
496         /// <param name="sender"></param>
497 
498         /// <param name="e"></param>
499 
500         private void comboPageSize_SelectedIndexChanged(object sender, EventArgs e)
501 
502         {
503 
504             this.PageSize = Convert.ToInt32(comboPageSize.Text);
505 
506             this.Bind();
507 
508         }
509 
510  
511 
512 }
513 
514  
515 
516 这里重点提两点:一是图片切换:
517 
518 this.btnFirst.Image = global::CHVM.Properties.Resources.page_first_disabled;
519 
520 Image对象是在Properties.Resource.resx中自动生成的,代码如下:
521 
522         internal static System.Drawing.Bitmap page_first {
523 
524             get {
525 
526                 object obj = ResourceManager.GetObject("page-first", resourceCulture);
527 
528                 return ((System.Drawing.Bitmap)(obj));
529 
530             }
531 
532         }
533 
534         
535 
536         internal static System.Drawing.Bitmap page_first_disabled {
537 
538             get {
539 
540                 object obj = ResourceManager.GetObject("page_first_disabled", resourceCulture);
541 
542                 return ((System.Drawing.Bitmap)(obj));
543 
544             }
545 
546     }
547 
548 二是应用了委托事件:我们在这定义了一个分页事件
549 
550 public event EventPagingHandler EventPaging;
551 
552 在数据绑定方法中实现它:
553 
554 /// <summary>
555 
556         /// 数据绑定
557 
558         /// </summary>
559 
560         public void Bind()
561 
562         {
563 
564             if (this.EventPaging != null)
565 
566             {
567 
568                 this.EventPaging(new EventArgs());
569 
570             }
571 
572             //… 以下省略
573 
574 }
575 
576 这里需要大家对C#的委托和事件有一定的了解,不清楚的可以直接使用,或者先去查阅相关参考资料,这里我们就不谈委托机制了。
577 
578  
579 
580 第三步:应用
581 
582 值得一提的是,WinForm并不能直接把用户自定控件往Windows窗体中拖拽,而自动生成实例(ASP.NET是可以直接拖拽的)。那么如果我们需要在应用中使用,只能自己修改Desginer.cs代码了。
583 
584 先声明:
585 
586 private CHVM.PagingControl.Paging paging1;
587 
588 然后在InitializeComponent()方法中实例化:
589 
590 this.paging1 = new CHVM.PagingControl.Paging();
591 
592     // 
593 
594     // paging1
595 
596     // 
597 
598     this.paging1.CurrentPage = 1;
599 
600     this.paging1.Location = new System.Drawing.Point(3, 347);
601 
602     this.paging1.Name = "paging1";
603 
604     this.paging1.PageCount = 0;
605 
606     this.paging1.PageSize = 50;
607 
608     this.paging1.Size = new System.Drawing.Size(512, 30);
609 
610     this.paging1.TabIndex = 8;
611 
612  this.paging1.TotalCount = 0; 
613 
614 //在这里注册事件
615 
616 this.paging1.EventPaging += new CHVM.PagingControl.EventPagingHandler(this.paging1_EventPaging); 
View Code

 

加完后就能看到效果了,相当于托了一个分页控件的效果:(如下图所示)

WinForm轻松实现自定义分页 _第3张图片

最后在事件中加入分页事件需要执行的代码:

 

  1  /// <summary>
  2 
  3         /// 分页事件
  4 
  5         /// </summary>
  6 
  7         /// <param name="e"></param>
  8 
  9         private void paging1_EventPaging(EventArgs e)
 10 
 11         {
 12 
 13             GvDataBind();   //DataGridView数据绑定
 14 
 15         }
 16 
 17         /// <summary>
 18 
 19         /// 查询
 20 
 21         /// </summary>
 22 
 23         /// <param name="sender"></param>
 24 
 25         /// <param name="e"></param>
 26 
 27         private void btnQuery_Click(object sender, EventArgs e)
 28 
 29         {
 30 
 31             paging1_EventPaging(e);
 32 
 33         }
 34 
 35         /// <summary>
 36 
 37         /// gvOperateLogList 数据邦定
 38 
 39         /// </summary>
 40 
 41         private void GvDataBind()
 42 
 43         {
 44 
 45             PagingCondition paging = new PagingCondition()
 46 
 47             {
 48 
 49                 startIndex=paging1.CurrentPage,
 50 
 51                 pageSize = paging1.PageSize
 52 
 53             };
 54 
 55             MultiCondition condition = new MultiCondition();
 56 
 57             condition.DateSign="FOperateTime";
 58 
 59             condition.BeginDate = dtBegin.Value;
 60 
 61             condition.EndDate = dtEnd.Value;
 62 
 63             if (comboOperator.Text != "")
 64 
 65             {
 66 
 67                 condition.Dict.Add("FOperator", comboOperator.Text);
 68 
 69             }
 70 
 71             if (comboType.Text != "")
 72 
 73             {
 74 
 75                 condition.Dict.Add("FType", comboType.Text);
 76 
 77             }
 78 
 79             if (comboObject.Text != "")
 80 
 81             {
 82 
 83                 condition.Dict.Add("FOptObject", comboObject.Text);
 84 
 85             }
 86 
 87             if (txtBoxContent.Text != "")
 88 
 89             {
 90 
 91                 condition.Dict.Add("FContent", txtBoxContent.Text);
 92 
 93             }
 94 
 95             DataTable dt = GetByCondition(paging, condition);
 96 
 97             paging1.TotalCount = Convert.ToInt32(dt.TableName);
 98 
 99             gvOperateLogList.DataSource = dt;
100 
101             gvOperateLogList.Columns.Clear();
102 
103             var dict = GetGvColumnsDict();
104 
105             DataGridViewHelp.DisplayColList(gvOperateLogList, dict);
106 
107         }
View Code

 

注:MultiCondition、PagingCondition是我专门针对分页综合查询定义的两个类,兴趣的话可以去了解一下:

查询条件就统一定义在MultiCondition中(详见:http://xuzhihong1987.blog.163.com/blog/static/267315872011294150763 ),

PagingCondition是分页条件(详见: http://xuzhihong1987.blog.163.com/blog/static/2673158720112941950801 ),

Extjs+LINQ轻松实现高级综合查询:

http://xuzhihong1987.blog.163.com/blog/static/2673158720112943356111/

其他:

 

 1  /// <summary>
 2 
 3         /// gv显示列设置
 4 
 5         /// </summary>
 6 
 7         /// <returns></returns>
 8 
 9         public Dictionary<string, string> GetGvColumnsDict()
10 
11         {
12 
13             Dictionary<string, string> dict = new Dictionary<string, string>();
14 
15             dict.Add("FTYPE", "操作类型");
16 
17             dict.Add("FOPTOBJECT", "操作对象");
18 
19             dict.Add("FCONTENT", "操作内容");
20 
21             dict.Add("FOperator", "操作人员");
22 
23             return dict;
24 
25         }
26 
27  
28 
29 DataGridViewHelp.DisplayColList是一个静态方法,为一个辅助类:
30 
31         /// <summary>
32 
33         /// 替换列表
34 
35         /// </summary>
36 
37         /// <param name="dgv">类表名称</param>
38 
39         /// <param name="dic">数据</param>
40 
41         /// <param name="isRM">是否显示序列号</param>
42 
43         public static void DisplayColList(DataGridView dgv, Dictionary<string, string> dic)//, bool isRM
44 
45         {
46 
47             _dgv = dgv;
48 
49             dgv.RowsDefaultCellStyle.BackColor = Color.FromArgb(255, 255, 255);//第一行   
50 
51             dgv.AlternatingRowsDefaultCellStyle.BackColor = Color.FromArgb(231, 232, 239);//第二行   
52 
53             dgv.GridColor = Color.FromArgb(207, 208, 216);//
54 
55             dgv.RowTemplate.Height = 25;//列宽
56 
57             dgv.AllowUserToAddRows=false;//无空行
58 
59             dgv.CellBorderStyle = DataGridViewCellBorderStyle.SingleVertical;
60 
61             dgv.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;
62 
63             dgv.AllowUserToOrderColumns = true;
64 
65             dgv.RowPostPaint += new DataGridViewRowPostPaintEventHandler(dgv_RowPostPaint);
66 
67             dgv.CellPainting += new DataGridViewCellPaintingEventHandler(dgv_CellPainting);//列头样式
68 
69             dgv.CellFormatting += new DataGridViewCellFormattingEventHandler(dgv_CellFormatting);//选中行样式
70 
71  
72 
73             foreach (KeyValuePair<string, string> cl in dic)
74 
75             {
76 
77                 dgv.AutoGenerateColumns = false;
78 
79                 DataGridViewTextBoxColumn obj = new DataGridViewTextBoxColumn();
80 
81                 obj.DataPropertyName = cl.Key;
82 
83                 obj.HeaderText = cl.Value;
84 
85                 obj.Name = cl.Key;
86 
87                 obj.Width = 100;
88 
89                 //obj.DefaultCellStyle.Padding.All = 10;
90 
91                 obj.Resizable = DataGridViewTriState.True;
92 
93                 dgv.Columns.AddRange(new DataGridViewColumn[] { obj });
94 
95             }
96 
97         }
98 
99  
View Code

 

到此实现就全部完成了,运行效果后就是前面所示的效果!也可以动态修改每页条数。

WinForm轻松实现自定义分页 _第4张图片

说在最后,改功能简单是简单,但是涉及到很多知识点,委托、事件、

DataGridView数据动态绑定,综合查询,我这里用的是Oracle数据库,如果用LINQ语法的话查询数据会比较方便,写起代码也会显得很优雅。

 

1 /// <summary>        /// 获取条件查询数据        /// </summary>        /// <param name="paging"></param>        /// <param name="conditon"></param>        /// <returns></returns>        private DataTable GetByCondition(PagingCondition paging, MultiCondition conditon)        {            string strSql = "select * from TOperateLog ";            string strSqlGetCount = "select count(1) from TOperateLog ";            string strWhere = " where 1=1 ";            if (conditon != null)            {                if (conditon.DateSign == "FOperateTime") //操作日期                {                    if (conditon.BeginDate != DateTime.MinValue)                    {                        strWhere += string.Format(" and FOperateTime>='{0}'", conditon.BeginDate.ToString("yyyy-MM-dd HH:mm:ss"));                    }                    if (conditon.EndDate != DateTime.MaxValue)                    {                        strWhere += string.Format(" and FOperateTime<='{0}'", conditon.EndDate.AddDays(1).ToString("yyyy-MM-dd HH:mm:ss"));                    }                }                var dict = conditon.Dict;                if (dict != null)                {                    foreach (var key in dict.Keys)                    {                        if (key.Equals("FType")) //操作类型                        {                            strWhere += string.Format(" and FType='{0}'", dict[key]);                        }                        if (key.Equals("FOperator")) //操作人员                        {                            strWhere += string.Format(" and FOperator='{0}'", dict[key]);                        }                        else if (key.Equals("FOptObject")) //操作对象                        {                            strWhere += string.Format(" and FOptObject='{0}'", dict[key]);                        }                        else if (key.Equals("FContent")) //操作内容                        {                            strWhere += string.Format(" and FContent like '%{0}%'", dict[key]);                        }                    }                }            }            strWhere += " order by FOperateTime ";            strSql += strWhere;            strSqlGetCount += strWhere;            if (paging != null)            {                if (paging.needPaging)                {                    //strSql = string.Format("select * from ( {0} ) where ROWNUM>={1} and ROWNUM<={2}", strSql, paging.startIndex, paging.startIndex + paging.pageSize-1);                    strSql = string.Format("select * from (select T.*,RowNum  RN from ({0})T where ROWNUM <={1}) where RN>={2} ",strSql, paging.startIndex + paging.pageSize - 1,paging.startIndex);                }            }            DataTable dt = DataCon.Query(strSql).Tables[0];            dt.TableName = DataCon.GetSingle(strSqlGetCount)+"";            return dt;        }
View Code

 

 

 

你可能感兴趣的:(WinForm)