WinForm轻松实现自定义分页 (转载)
转载至http://xuzhihong1987.blog.163.com/blog/static/267315872011315114240140/
以前都是做web开发,最近接触了下WinForm,发现WinForm分页控件好像都没有,网上搜索了一下,发现有很多网友写的分页控件,分页效果应该都能实现吧,只是其风格都不是很符合我想要的。做web的时候,我习惯了Extjs的Grid分页效果,所以也想在WinForm中做个类似的效果,所以咬咬牙,做个山寨版本的吧,虽然自己写费时费力,在项目进度考虑中不是很可取,但是还是特别想山寨一回,做自己喜欢的风格。
按照惯例,还是先看看实现效果图吧(有图有真像,才好继续下文呀)
应用效果:(效果有点难看,因为我是刚装的
xp系统,还是经典主题,如果换成Win7系统或其他主题,效果还是会很不错的)
我们要做的就是上图显示的一个自定义控件,这个效果参考自我做
web开发使用的Extjs之Grid的分页效果(如下图)
Extjs的动画效果我们暂时就不实现了,这里只做个外观看起来想像即可,完全一样就脱离“山寨”概念了,总要比人家差点吧,谁让咱是模仿呢!
言归正传,我们现在就看看具体怎么实现吧:
第一步:先布局
注:我们创建的是用户自定义控件,而不是WinForm窗体
就是先做出个显示效果,这个布局很简单,在这就不多说,重点就是“首页、前一页、后一页、末页”图标,每个图标分两种,一是能点击的高亮效果,一个是灰色不不能点击。以下是套图:(大家如果不喜欢,可以去做成自己喜欢的风格图片)
第二步:编写分页代码
布局好了,那么第二步我们就要代码实现正确显示文字信息,分页事件,每页条数选择事件,公开属性和事件。以下是完整代码:
/// <summary> /// 声明委托 /// </summary> /// <param name="e"></param> public delegate void EventPagingHandler(EventArgs e); public partial class Paging : UserControl { public Paging() { InitializeComponent(); } public event EventPagingHandler EventPaging; #region 公开属性 private int _pageSize = ; /// <summary> /// 每页显示记录数(默认50) /// </summary> public int PageSize { get { return _pageSize; } set { if (value > ) { _pageSize = value; } else { _pageSize = ; } this.comboPageSize.Text = _pageSize.ToString(); } } private int _currentPage = ; /// <summary> /// 当前页 /// </summary> public int CurrentPage { get { return _currentPage; } set { if (value > ) { _currentPage = value; } else { _currentPage = ; } } } private int _totalCount = ; /// <summary> /// 总记录数 /// </summary> public int TotalCount { get { return _totalCount; } set { if (value>=) { _totalCount = value; } else { _totalCount = ; } this.lblTotalCount.Text = this._totalCount.ToString(); CalculatePageCount(); this.lblRecordRegion.Text = GetRecordRegion(); } } private int _pageCount = ; /// <summary> /// 页数 /// </summary> public int PageCount { get { return _pageCount; } set { if (value>=) { _pageCount = value; } else { _pageCount = ; } this.lblPageCount.Text = _pageCount + ""; } } #endregion /// <summary> /// 计算页数 /// </summary> private void CalculatePageCount() { if (this.TotalCount>) { this.PageCount = Convert.ToInt32(Math.Ceiling(Convert.ToDouble(this.TotalCount) / Convert.ToDouble(this.PageSize))); } else { this.PageCount = ; } } /// <summary> /// 获取显示记录区间(格式如:1-50) /// </summary> /// <returns></returns> private string GetRecordRegion() { if (this.PageCount == ) //只有一页 { return "1-" + this.TotalCount.ToString(); } else //有多页 { if(this.CurrentPage==) //当前显示为第一页 { return "1-"+this.PageSize; } else if(this.CurrentPage==this.PageCount) //当前显示为最后一页 { return ((this.CurrentPage-)*this.PageSize+) +"-"+this.TotalCount; } else //中间页 { return ((this.CurrentPage-) * this.PageSize+) + "-" + this.CurrentPage * this.PageSize; } } } /// <summary> /// 数据绑定 /// </summary> public void Bind() { if (this.EventPaging != null) { this.EventPaging(new EventArgs()); } if (this.CurrentPage>this.PageCount) { this.CurrentPage = this.PageCount; } this.txtBoxCurPage.Text = this.CurrentPage+""; this.lblTotalCount.Text = this.TotalCount+""; this.lblPageCount.Text = this.PageCount+""; this.lblRecordRegion.Text = GetRecordRegion(); if (this.CurrentPage==) { this.btnFirst.Enabled = false; this.btnPrev.Enabled = false; this.btnFirst.Image = global::CHVM.Properties.Resources.page_first_disabled; this.btnPrev.Image = global::CHVM.Properties.Resources.page_prev_disabled; } else { this.btnFirst.Enabled = true; this.btnPrev.Enabled = true; this.btnFirst.Image = global::CHVM.Properties.Resources.page_first; this.btnPrev.Image = global::CHVM.Properties.Resources.page_prev; } if (this.CurrentPage == this.PageCount) { this.btnNext.Enabled = false; this.btnLast.Enabled = false; this.btnNext.Image = global::CHVM.Properties.Resources.page_next_disabled; this.btnLast.Image = global::CHVM.Properties.Resources.page_last_disabled; } else { this.btnNext.Enabled = true; this.btnLast.Enabled = true; this.btnNext.Image = global::CHVM.Properties.Resources.page_next; this.btnLast.Image = global::CHVM.Properties.Resources.page_last; } if (this.TotalCount==) { this.btnFirst.Enabled = false; this.btnPrev.Enabled = false; this.btnNext.Enabled = false; this.btnLast.Enabled = false; this.btnFirst.Image = global::CHVM.Properties.Resources.page_first_disabled; this.btnPrev.Image = global::CHVM.Properties.Resources.page_prev_disabled; this.btnNext.Image = global::CHVM.Properties.Resources.page_next_disabled; this.btnLast.Image = global::CHVM.Properties.Resources.page_last_disabled; } } private void btnFirst_Click(object sender, EventArgs e) { this.CurrentPage = ; this.Bind(); } private void btnPrev_Click(object sender, EventArgs e) { this.CurrentPage -= ; this.Bind(); } private void btnNext_Click(object sender, EventArgs e) { this.CurrentPage += ; this.Bind(); } private void btnLast_Click(object sender, EventArgs e) { this.CurrentPage = this.PageCount; this.Bind(); } /// <summary> /// 改变每页条数 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void comboPageSize_SelectedIndexChanged(object sender, EventArgs e) { this.PageSize = Convert.ToInt32(comboPageSize.Text); this.Bind(); } } 这里重点提两点:一是图片切换: this.btnFirst.Image = global::CHVM.Properties.Resources.page_first_disabled; Image对象是在Properties.Resource.resx中自动生成的,代码如下: internal static System.Drawing.Bitmap page_first { get { object obj = ResourceManager.GetObject("page-first", resourceCulture); return ((System.Drawing.Bitmap)(obj)); } } internal static System.Drawing.Bitmap page_first_disabled { get { object obj = ResourceManager.GetObject("page_first_disabled", resourceCulture); return ((System.Drawing.Bitmap)(obj)); } } 二是应用了委托事件:我们在这定义了一个分页事件 public event EventPagingHandler EventPaging; 在数据绑定方法中实现它: /// <summary> /// 数据绑定 /// </summary> public void Bind() { if (this.EventPaging != null) { this.EventPaging(new EventArgs()); } //… 以下省略 } 这里需要大家对C#的委托和事件有一定的了解,不清楚的可以直接使用,或者先去查阅相关参考资料,这里我们就不谈委托机制了。 第三步:应用 值得一提的是,WinForm并不能直接把用户自定控件往Windows窗体中拖拽,而自动生成实例(ASP.NET是可以直接拖拽的)。那么如果我们需要在应用中使用,只能自己修改Desginer.cs代码了。 先声明: private CHVM.PagingControl.Paging paging1; 然后在InitializeComponent()方法中实例化: this.paging1 = new CHVM.PagingControl.Paging(); // // paging1 // this.paging1.CurrentPage = ; this.paging1.Location = new System.Drawing.Point(, ); this.paging1.Name = "paging1"; this.paging1.PageCount = ; this.paging1.PageSize = ; this.paging1.Size = new System.Drawing.Size(, ); this.paging1.TabIndex = ; this.paging1.TotalCount = ; //在这里注册事件 this.paging1.EventPaging += new CHVM.PagingControl.EventPagingHandler(this.paging1_EventPaging);
加完后就能看到效果了,相当于托了一个分页控件的效果:(如下图所示)
最后在事件中加入分页事件需要执行的代码:
/// <summary> /// 分页事件 /// </summary> /// <param name="e"></param> private void paging1_EventPaging(EventArgs e) { GvDataBind(); //DataGridView数据绑定 } /// <summary> /// 查询 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btnQuery_Click(object sender, EventArgs e) { paging1_EventPaging(e); } /// <summary> /// gvOperateLogList 数据邦定 /// </summary> private void GvDataBind() { PagingCondition paging = new PagingCondition() { startIndex=paging1.CurrentPage, pageSize = paging1.PageSize }; MultiCondition condition = new MultiCondition(); condition.DateSign="FOperateTime"; condition.BeginDate = dtBegin.Value; condition.EndDate = dtEnd.Value; if (comboOperator.Text != "") { condition.Dict.Add("FOperator", comboOperator.Text); } if (comboType.Text != "") { condition.Dict.Add("FType", comboType.Text); } if (comboObject.Text != "") { condition.Dict.Add("FOptObject", comboObject.Text); } if (txtBoxContent.Text != "") { condition.Dict.Add("FContent", txtBoxContent.Text); } DataTable dt = GetByCondition(paging, condition); paging1.TotalCount = Convert.ToInt32(dt.TableName); gvOperateLogList.DataSource = dt; gvOperateLogList.Columns.Clear(); var dict = GetGvColumnsDict(); DataGridViewHelp.DisplayColList(gvOperateLogList, dict); }
注: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/
其他:
/// <summary> /// gv显示列设置 /// </summary> /// <returns></returns> public Dictionary<string, string> GetGvColumnsDict() { Dictionary<string, string> dict = new Dictionary<string, string>(); dict.Add("FTYPE", "操作类型"); dict.Add("FOPTOBJECT", "操作对象"); dict.Add("FCONTENT", "操作内容"); dict.Add("FOperator", "操作人员"); return dict; } DataGridViewHelp.DisplayColList是一个静态方法,为一个辅助类: /// <summary> /// 替换列表 /// </summary> /// <param name="dgv">类表名称</param> /// <param name="dic">数据</param> /// <param name="isRM">是否显示序列号</param> public static void DisplayColList(DataGridView dgv, Dictionary<string, string> dic)//, bool isRM { _dgv = dgv; dgv.RowsDefaultCellStyle.BackColor = Color.FromArgb(, , );//第一行 dgv.AlternatingRowsDefaultCellStyle.BackColor = Color.FromArgb(, , );//第二行 dgv.GridColor = Color.FromArgb(, , );// dgv.RowTemplate.Height = ;//列宽 dgv.AllowUserToAddRows=false;//无空行 dgv.CellBorderStyle = DataGridViewCellBorderStyle.SingleVertical; dgv.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill; dgv.AllowUserToOrderColumns = true; dgv.RowPostPaint += new DataGridViewRowPostPaintEventHandler(dgv_RowPostPaint); dgv.CellPainting += new DataGridViewCellPaintingEventHandler(dgv_CellPainting);//列头样式 dgv.CellFormatting += new DataGridViewCellFormattingEventHandler(dgv_CellFormatting);//选中行样式 foreach (KeyValuePair<string, string> cl in dic) { dgv.AutoGenerateColumns = false; DataGridViewTextBoxColumn obj = new DataGridViewTextBoxColumn(); obj.DataPropertyName = cl.Key; obj.HeaderText = cl.Value; obj.Name = cl.Key; obj.Width = ; //obj.DefaultCellStyle.Padding.All = 10; obj.Resizable = DataGridViewTriState.True; dgv.Columns.AddRange(new DataGridViewColumn[] { obj }); } }
到此实现就全部完成了,运行效果后就是前面所示的效果!也可以动态修改每页条数。
说在最后,改功能简单是简单,但是涉及到很多知识点,委托、事件、
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; }
WinForm轻松实现自定义分页 (转载)的更多相关文章
- winform中DataGridView实现分页功能
WinForm轻松实现自定义分页 (转载) WinForm轻松实现自定义分页 (转载) 转载至http://xuzhihong1987.blog.163.com/blog/static/26731 ...
- C# DataGridView自定义分页控件
好些日子不仔细写C#代码了,现在主要是Java项目,C#.Net相关项目不多了,有点手生了,以下代码不足之处望各位提出建议和批评. 近日闲来无事想研究一下自定义控件,虽然之前也看过,那也仅限于皮毛,粗 ...
- 雷林鹏分享:jQuery EasyUI 数据网格 - 自定义分页
jQuery EasyUI 数据网格 - 自定义分页 数据网格(datagrid)内置一个很好特性的分页功能,自定义也相当简单.在本教程中,我们将创建一个数据网格(datagrid),并在分页工具栏上 ...
- Android Launcher分析和修改11——自定义分页指示器(paged_view_indicator)
Android4.0的Launcher自带了一个简单的分页指示器,就是Hotseat上面那个线段,这个本质上是一个ImageView利用.9.png图片做,效果实在是不太美观,用测试人员的话,太丑了. ...
- asp.net webform 自定义分页控件
做web开发一直用到分页控件,自己也动手实现了个,使用用户自定义控件. 翻页后数据加载使用委托,将具体实现放在在使用分页控件的页面进行注册. 有图有真相,给个直观的认识: 自定义分页控件前台代码: & ...
- Python之路【第十九篇】自定义分页实现(模块化)
自定义分页 1.目的&环境准备 目的把分页写成一个模块的方式然后在需要分页的地方直接调用模块就行了. 环境准备Django中生成一个APP并且注册,配置URL&Views 配置URL ...
- MVC下分页的自定义分页一种实现
1.引言 在MVC开发中我们经常会对数据进行分页的展示.通过分页我们可以从服务端获取指定的数据来进行展示.这样既节约了数据库查询的时间也节约了网络传输的数据量.在MVC开发中使用的比较多的应该是MVC ...
- Django自定义分页、bottle、Flask
一.使用django实现之定义分页 1.自定义分页在django模板语言中,通过a标签实现; 2.前段a标签使用<a href="/user_list/?page=1"> ...
- Mvc自定义分页控件
MVC开发分页常常使用第三方控件,生成的分页HTML带有版权申明,虽然免费,但是总有的别扭.于是,某日,楼主闲来蛋疼,折腾了个自定义分页控件: 先来展示下效果图: 1>当分页不超过10页的时候, ...
随机推荐
- 终端改变host的类型,还原
- 【C语言入门教程】7.3 结构体指针的定义和引用
C 语言中指针的操作非常灵活,它也能指向结构体变量对结构体变量进行操作.在学习结构指针之前,需要再次加深对指针的认识.声明指针变量时所使用的数据类型修饰符实际上的作用是定义指针访问内存的范围,如果指针 ...
- RDS记录
rdsafbnr32uzayn.mysql.rds.aliyuncs.com r7fysfqs90r74cm6
- Linux资源站
1.<鸟哥的linux私房菜>中提供的台湾高速网络中心ftp站:http://ftp.twaren.net/Linux/CentOS/5/
- 我的Java书单之优秀的入门书
我始终相信,学习任何一门新技术,该技术相关的优秀书籍总是最好的资料.当然了,优秀的视频教程能帮组你快速地了解该技术,但是要深入和系统地去学习该技术,好的书籍就显得尤为重要了.结合我自己学习java的经 ...
- 教你如何在Kali Linux 环境下设置蜜罐?
导读 Pentbox是一个包含了许多可以使渗透测试工作变得简单流程化的工具的安全套件.它是用Ruby编写并且面向GNU/Linux,同时也支持Windows.MacOS和其它任何安装有Ruby的系统. ...
- c++ 操作符重载和友元
操作符重载(operator overloading)是C++中的一种多态,C++允许用户自定义函数名称相同但参数列表不同的函数,这被称为函数重载或函数多态.操作符重载函数的格式一般为: operat ...
- 【VBA】批量插入图片
解决如下问题: 需要批量导入图片到Excel 图片放在一个文件夹中 图片有严格的顺序关系,即按照:共通名_编号的方式命名. 图片格式统一,即均为同一格式. 有两种方式可以插入图片到Excel中,其一为 ...
- 文本比较算法三——SUNDAY 算法
SUNDAY 算法描述: 字符串查找算法中,最著名的两个是KMP算法(Knuth-Morris-Pratt)和BM算法(Boyer-Moore).两个算法在最坏情况下均具有线性的查找时间.但是在实用上 ...
- Vijos P1769 网络的关键边
Description 一个连通的无向图,有些点有A属性,有些点有B属性,可以同时具有.删掉某条边后,如果使得连通块中一些点不具有A,B属性的点,求这些边. Sol Tarjan求割边. 首先这些边一 ...