轉載至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 /// </summary> 4 /// <param name="e"></param> 5 public delegate void EventPagingHandler (EventArgs e); 6 public partial class Paging : UserControl 7 { 8 public Paging() 9 { 10 InitializeComponent(); 11 } 12 public event EventPagingHandler EventPaging; 13 #region 公開屬性 14 private int _pageSize = 50; 15 /// <summary> 16 /// 每頁顯示記錄數(默認50) 17 /// </summary> 18 public int PageSize 19 { 20 get 21 { 22 return _pageSize; 23 } 24 set 25 { 26 if (value > 0) 27 { 28 _pageSize = value; 29 } 30 else 31 { 32 _pageSize = 50; 33 } 34 this.comboPageSize.Text = _pageSize.ToString(); 35 } 36 } 37 private int _currentPage = 1; 38 /// <summary> 39 /// 當前頁 40 /// </summary> 41 public int CurrentPage 42 { 43 get 44 { 45 return _currentPage; 46 } 47 set 48 { 49 if (value > 0) 50 { 51 _currentPage = value; 52 } 53 else 54 { 55 _currentPage = 1; 56 } 57 58 } 59 } 60 private int _totalCount = 0; 61 /// <summary> 62 /// 總記錄數 63 /// </summary> 64 public int TotalCount 65 { 66 get 67 { 68 return _totalCount; 69 } 70 set 71 { 72 if (value >= 0) 73 { 74 _totalCount = value; 75 } 76 else 77 { 78 _totalCount = 0; 79 } 80 this.lblTotalCount.Text = this._totalCount.ToString(); 81 CalculatePageCount(); 82 this.lblRecordRegion.Text = GetRecordRegion(); 83 } 84 } 85 86 private int _pageCount = 0; 87 /// <summary> 88 /// 頁數 89 /// </summary> 90 public int PageCount 91 { 92 get 93 { 94 return _pageCount; 95 } 96 set 97 { 98 if (value >= 0) 99 { 100 _pageCount = value; 101 } 102 else 103 { 104 _pageCount = 0; 105 } 106 this.lblPageCount.Text = _pageCount + ""; 107 } 108 } 109 #endregion 110 111 /// <summary> 112 /// 計算頁數 113 /// </summary> 114 private void CalculatePageCount() 115 { 116 if (this.TotalCount > 0) 117 { 118 this.PageCount = Convert.ToInt32 (Math.Ceiling (Convert.ToDouble (this.TotalCount) / Convert.ToDouble (this.PageSize) ) ); 119 } 120 else 121 { 122 this.PageCount = 0; 123 } 124 } 125 126 /// <summary> 127 /// 獲取顯示記錄區間(格式如:1-50) 128 /// </summary> 129 /// <returns></returns> 130 private string GetRecordRegion() 131 { 132 if (this.PageCount == 1) //只有一頁 133 { 134 return "1-" + this.TotalCount.ToString(); 135 } 136 else //有多頁 137 { 138 if (this.CurrentPage == 1) //當前顯示為第一頁 139 { 140 return "1-" + this.PageSize; 141 } 142 else if (this.CurrentPage == this.PageCount) //當前顯示為最后一頁 143 { 144 return ( (this.CurrentPage - 1) * this.PageSize + 1) + "-" + this.TotalCount; 145 } 146 else //中間頁 147 { 148 return ( (this.CurrentPage - 1) * this.PageSize + 1) + "-" + this.CurrentPage * this.PageSize; 149 } 150 } 151 } 152 153 /// <summary> 154 /// 數據綁定 155 /// </summary> 156 public void Bind() 157 { 158 if (this.EventPaging != null) 159 { 160 this.EventPaging (new EventArgs() ); 161 } 162 if (this.CurrentPage > this.PageCount) 163 { 164 this.CurrentPage = this.PageCount; 165 } 166 this.txtBoxCurPage.Text = this.CurrentPage + ""; 167 this.lblTotalCount.Text = this.TotalCount + ""; 168 this.lblPageCount.Text = this.PageCount + ""; 169 this.lblRecordRegion.Text = GetRecordRegion(); 170 if (this.CurrentPage == 1) 171 { 172 this.btnFirst.Enabled = false; 173 this.btnPrev.Enabled = false; 174 this.btnFirst.Image = global::CHVM.Properties.Resources.page_first_disabled; 175 this.btnPrev.Image = global::CHVM.Properties.Resources.page_prev_disabled; 176 } 177 else 178 { 179 this.btnFirst.Enabled = true; 180 this.btnPrev.Enabled = true; 181 this.btnFirst.Image = global::CHVM.Properties.Resources.page_first; 182 this.btnPrev.Image = global::CHVM.Properties.Resources.page_prev; 183 } 184 if (this.CurrentPage == this.PageCount) 185 { 186 this.btnNext.Enabled = false; 187 this.btnLast.Enabled = false; 188 this.btnNext.Image = global::CHVM.Properties.Resources.page_next_disabled; 189 this.btnLast.Image = global::CHVM.Properties.Resources.page_last_disabled; 190 } 191 else 192 { 193 this.btnNext.Enabled = true; 194 this.btnLast.Enabled = true; 195 this.btnNext.Image = global::CHVM.Properties.Resources.page_next; 196 this.btnLast.Image = global::CHVM.Properties.Resources.page_last; 197 } 198 if (this.TotalCount == 0) 199 { 200 this.btnFirst.Enabled = false; 201 this.btnPrev.Enabled = false; 202 this.btnNext.Enabled = false; 203 this.btnLast.Enabled = false; 204 this.btnFirst.Image = global::CHVM.Properties.Resources.page_first_disabled; 205 this.btnPrev.Image = global::CHVM.Properties.Resources.page_prev_disabled; 206 this.btnNext.Image = global::CHVM.Properties.Resources.page_next_disabled; 207 this.btnLast.Image = global::CHVM.Properties.Resources.page_last_disabled; 208 } 209 } 210 211 private void btnFirst_Click (object sender, EventArgs e) 212 { 213 this.CurrentPage = 1; 214 this.Bind(); 215 } 216 217 private void btnPrev_Click (object sender, EventArgs e) 218 { 219 this.CurrentPage -= 1; 220 this.Bind(); 221 } 222 223 private void btnNext_Click (object sender, EventArgs e) 224 { 225 this.CurrentPage += 1; 226 this.Bind(); 227 } 228 229 private void btnLast_Click (object sender, EventArgs e) 230 { 231 this.CurrentPage = this.PageCount; 232 this.Bind(); 233 } 234 235 /// <summary> 236 /// 改變每頁條數 237 /// </summary> 238 /// <param name="sender"></param> 239 /// <param name="e"></param> 240 private void comboPageSize_SelectedIndexChanged (object sender, EventArgs e) 241 { 242 this.PageSize = Convert.ToInt32 (comboPageSize.Text); 243 this.Bind(); 244 } 245 } 246 247 這里重點提兩點:一是圖片切換: 248 this.btnFirst.Image = global::CHVM.Properties.Resources.page_first_disabled; 249 Image對象是在Properties.Resource.resx中自動生成的,代碼如下: 250 internal static System.Drawing.Bitmap page_first 251 { 252 get { 253 object obj = ResourceManager.GetObject ("page-first", resourceCulture); 254 return ( (System.Drawing.Bitmap) (obj) ); 255 } 256 } 257 258 internal static System.Drawing.Bitmap page_first_disabled 259 { 260 get { 261 object obj = ResourceManager.GetObject ("page_first_disabled", resourceCulture); 262 return ( (System.Drawing.Bitmap) (obj) ); 263 } 264 } 265 二是應用了委托事件:我們在這定義了一個分頁事件 266 public event EventPagingHandler EventPaging; 267 在數據綁定方法中實現它: 268 /// <summary> 269 /// 數據綁定 270 /// </summary> 271 public void Bind() 272 { 273 if (this.EventPaging != null) 274 { 275 this.EventPaging (new EventArgs() ); 276 } 277 //… 以下省略 278 } 279 這里需要大家對C#的委托和事件有一定的了解,不清楚的可以直接使用,或者先去查閱相關參考資料,這里我們就不談委托機制了。 280 281 第三步:應用 282 值得一提的是,WinForm並不能直接把用戶自定控件往Windows窗體中拖拽,而自動生成實例(ASP.NET是可以直接拖拽的)。那么如果我們需要在應用中使用,只能自己修改Desginer.cs代碼了。 283 先聲明: 284 private CHVM.PagingControl.Paging paging1; 285 然后在InitializeComponent() 方法中實例化: 286 this.paging1 = new CHVM.PagingControl.Paging(); 287 // 288 // paging1 289 // 290 this.paging1.CurrentPage = 1; 291 this.paging1.Location = new System.Drawing.Point (3, 347); 292 this.paging1.Name = "paging1"; 293 this.paging1.PageCount = 0; 294 this.paging1.PageSize = 50; 295 this.paging1.Size = new System.Drawing.Size (512, 30); 296 this.paging1.TabIndex = 8; 297 this.paging1.TotalCount = 0; 298 //在這里注冊事件 299 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/
其他:

到此實現就全部完成了,運行效果后就是前面所示的效果!也可以動態修改每頁條數。
說在最后,改功能簡單是簡單,但是涉及到很多知識點,委托、事件、
DataGridView數據動態綁定,綜合查詢,我這里用的是Oracle數據庫,如果用LINQ語法的話查詢數據會比較方便,寫起代碼也會顯得很優雅。
/// <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;
}
==========================================================================
C#開發WinForm分頁控件
閑暇之余,自己動手做了個分頁控件,真是受益良多
WinFormPager.dll控件下載地址 WinFormPager源代碼下載地址
以下是調用分頁控件WinFormPager方法:
//第一步:指定返回的記錄數
winFormPager1.RecordCount = 返回記錄數;
//第二步:在控件的PageChanged事件中執行綁定DataGridView的方法
private void winFormPager1_PageChanged()
{
dataGridView1.DataSource = GetList(winFormPager1.PageSize,winFormPager1.CurrentPage);//GetList為獲取數據庫記錄方法,不介紹
}
//注:完成以上步驟就可成功調用,其余PageSize屬性等可在屬性瀏覽器中設置
以下是分頁控件WinformPager完整代碼:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using DevComponents.DotNetBar;
namespace WinFormPager
{
public partial class WinFormPager : UserControl
{
int currentPage = 1;//當前頁
/// <summary>
/// 當前頁
/// </summary>
[Description("當前頁"), Category("分頁設置")]
public int CurrentPage
{
get { return currentPage; }
set { currentPage = value; }
}
int pageSize = 10;//每頁顯示條數
/// <summary>
/// 每頁顯示條數
/// </summary>
[Description("每頁顯示條數"), Category("分頁設置")]
public int PageSize
{
get { return pageSize; }
set { pageSize = value; }
}
int pageTotal = 0;//總共多少頁
/// <summary>
/// 總共多少頁
/// </summary>
[Description("總共多少頁"), Category("分頁設置")]
public int PageTotal
{
get { return pageTotal; }
set { pageTotal = value; }
}
int currentGroup = 1;//當前組
/// <summary>
/// 當前組
/// </summary>
[Description("當前組"), Category("分頁設置")]
public int CurrentGroup
{
get { return currentGroup; }
set { currentGroup = value; }
}
int groupSize = 10;//每組顯示頁數
/// <summary>
/// 每組顯示頁數
/// </summary>
[Description("每組顯示頁數"), Category("分頁設置")]
public int GroupSize
{
get { return groupSize; }
set { groupSize = value; }
}
int groupTotal = 0;//總共多少組
/// <summary>
/// 總共多少組
/// </summary>
[Description("總共多少組"), Category("分頁設置")]
public int GroupTotal
{
get { return groupTotal; }
set { groupTotal = value; }
}
/// <summary>
/// 總的記錄數
/// </summary>
private int recordCount;//總的記錄數
[Description("總的記錄數"), Category("分頁設置")]
public int RecordCount
{
get { return recordCount; }
set
{
recordCount = value;
InitData();// 初始化數據
PageChanged();//當前頁改變事件
}
}
private int buttonWidth = 20;//按鈕寬度
/// <summary>
/// 按鈕寬度
/// </summary>
[Description("按鈕寬度"), Category("分頁設置")]
public int ButtonWidth
{
get { return buttonWidth; }
set { buttonWidth = value; }
}
private int buttonHeight = 23;//按鈕高度
/// <summary>
/// 按鈕高度
/// </summary>
[Description("按鈕高度"), Category("分頁設置")]