首页 > 代码库 > WinForm轻松实现自定义分页 (转载)

WinForm轻松实现自定义分页 (转载)

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

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

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

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

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

 

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

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

 

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

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

 

第一步:先布局

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

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

第二步:编写分页代码

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

 

  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                 else120 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 TotalCount142 143         {144 145             get146 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                 else166 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 PageCount194 195         {196 197             get198 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                 else218 219                 {220 221                     _pageCount = 0;222 223                 }224 225                 this.lblPageCount.Text = _pageCount + "";226 227             }228 229         }230 231  232 233        #endregion234 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             else256 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             else373 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             else401 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     // paging1595 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

 

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

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

 

  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 isRM44 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

 

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

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

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