WinForm轻松实现自定义分页

时间:2022-09-11 14:10:34

以前都是做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 = 50;

/// <summary>

/// 每页显示记录数(默认50)

/// </summary>

public int PageSize

{

get

{

return _pageSize;

}

set

{

if (value > 0)

{

_pageSize = value;

}

else

{

_pageSize = 50;

}

this.comboPageSize.Text = _pageSize.ToString();

}

}

private int _currentPage = 1;

/// <summary>

/// 当前页

/// </summary>

public int CurrentPage

{

get

{

return _currentPage;

}

set

{

if (value > 0)

{

_currentPage = value;

}

else

{

_currentPage = 1;

}



}

}

private int _totalCount = 0;

/// <summary>

/// 总记录数

/// </summary>

public int TotalCount

{

get

{

return _totalCount;

}

set

{

if (value>=0)

{

_totalCount = value;

}

else

{

_totalCount = 0;

}

this.lblTotalCount.Text = this._totalCount.ToString();

CalculatePageCount();

this.lblRecordRegion.Text = GetRecordRegion();

}

}



private int _pageCount = 0;

/// <summary>

/// 页数

/// </summary>

public int PageCount

{

get

{

return _pageCount;

}

set

{

if (value>=0)

{

_pageCount = value;

}

else

{

_pageCount = 0;

}

this.lblPageCount.Text = _pageCount + "";

}

}



#endregion



/// <summary>

/// 计算页数

/// </summary>

private void CalculatePageCount()

{

if (this.TotalCount>0)

{

this.PageCount = Convert.ToInt32(Math.Ceiling(Convert.ToDouble(this.TotalCount) / Convert.ToDouble(this.PageSize)));

}

else

{

this.PageCount = 0;

}

}



/// <summary>

/// 获取显示记录区间(格式如:1-50)

/// </summary>

/// <returns></returns>

private string GetRecordRegion()

{

if (this.PageCount == 1) //只有一页

{

return "1-" + this.TotalCount.ToString();

}

else //有多页

{

if(this.CurrentPage==1) //当前显示为第一页

{

return "1-"+this.PageSize;

}

else if(this.CurrentPage==this.PageCount) //当前显示为最后一页

{

return ((this.CurrentPage-1)*this.PageSize+1) +"-"+this.TotalCount;

}

else //中间页

{

return ((this.CurrentPage-1) * this.PageSize+1) + "-" + 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==1)

{

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==0)

{

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 = 1;

this.Bind();

}



private void btnPrev_Click(object sender, EventArgs e)

{

this.CurrentPage -= 1;

this.Bind();

}



private void btnNext_Click(object sender, EventArgs e)

{

this.CurrentPage += 1;

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 = 1;

this.paging1.Location = new System.Drawing.Point(3, 347);

this.paging1.Name = "paging1";

this.paging1.PageCount = 0;

this.paging1.PageSize = 50;

this.paging1.Size = new System.Drawing.Size(512, 30);

this.paging1.TabIndex = 8;

this.paging1.TotalCount = 0;

//在这里注册事件

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(255, 255, 255);//第一行

dgv.AlternatingRowsDefaultCellStyle.BackColor = Color.FromArgb(231, 232, 239);//第二行

dgv.GridColor = Color.FromArgb(207, 208, 216);//

dgv.RowTemplate.Height = 25;//列宽

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 = 100;

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

来自:http://www.cnblogs.com/markli/p/3863173.html