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

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

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

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

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

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

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

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

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

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

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

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

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

第一步:先布局

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

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

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

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); 

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

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

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

  /// <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 });

             }

         }

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

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

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

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;        }
上一篇:如何通过VMware安装Linux CentOS 7.7系统


下一篇:关于SAP CRM中间件系统搭建中遇到的一些问题