轉載至http://xuzhihong1987.blog.163.com/blog/static/267315872011315114240140/web
之前都是作web開發,最近接觸了下WinForm,發現WinForm分頁控件好像都沒有,網上搜索了一下,發現有不少網友寫的分頁控件,分頁效果應該都能實現吧,只是其風格都不是很符合我想要的。作web的時候,我習慣了Extjs的Grid分頁效果,因此也想在WinForm中作個相似的效果,因此咬咬牙,作個山寨版本的吧,雖然本身寫費時費力,在項目進度考慮中不是很可取,可是仍是特別想山寨一回,作本身喜歡的風格。數據庫
按照慣例,仍是先看看實現效果圖吧(有圖有真像,纔好繼續下文呀)ide
應用效果:(效果有點難看,由於我是剛裝的佈局
xp系統,仍是經典主題,若是換成Win7系統或其餘主題,效果仍是會很不錯的)動畫
咱們要作的就是上圖顯示的一個自定義控件,這個效果參考自我作this
web開發使用的Extjs之Grid的分頁效果(以下圖)spa
Extjs的動畫效果咱們暫時就不實現了,這裏只作個外觀看起來想像便可,徹底同樣就脫離「山寨」概念了,總要比人家差點吧,誰讓咱是模仿呢!3d
言歸正傳,咱們如今就看看具體怎麼實現吧:code
第一步:先佈局orm
注:咱們建立的是用戶自定義控件,而不是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 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);
加完後就能看到效果了,至關於託了一個分頁控件的效果:(以下圖所示)
最後在事件中加入分頁事件須要執行的代碼:
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 }
注: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
到此實現就所有完成了,運行效果後就是前面所示的效果!也能夠動態修改每頁條數。
說在最後,改功能簡單是簡單,可是涉及到不少知識點,委託、事件、
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; }