DataGridView右键菜单自定义显示及隐藏列功能
WinForm程序中表单的列可自定义显示及隐藏,是一种常见的功能,对于用户体验来说是非常好的。笔者经过一段时间的摸索,终于实现了自己想要的功能及效果,现记录一下过程:
1、新建一个自定义控件,命名为:PopupMenuControl。
2、在PopupMenuControl.Designet文件中的InitializeComponent()方法下面,注册以下事件:
this.Paint+=newSystem.Windows.Forms.PaintEventHandler(this.PopupMenuControl_Paint); this.MouseDown+=newSystem.Windows.Forms.MouseEventHandler(this.PopupMenuControl_MouseDown); this.MouseMove+=newSystem.Windows.Forms.MouseEventHandler(this.PopupMenuControl_MouseMove);
3、PopupMenuControl的代码:
publicpartialclassPopupMenuControl:UserControl {publicdelegatevoidCheckedChanged(inthitIndex,boolisChecked);//勾选改变委托 publiceventCheckedChangedCheckedChangedEvent;//勾选改变事件 PopupMenuHelperpopupMenuHelper=null;//菜单帮助类,主要负责菜单绘制。 publicPopupMenuControl() { InitializeComponent(); } publicvoidInitialize(DataGridViewdgvTarget) { //菜单帮助类实例化 popupMenuHelper=newPopupMenuHelper(); //将列标题添加到items foreach(DataGridViewColumncolumnindgvTarget.Columns) { popupMenuHelper.AddItem(column.HeaderText,column.Visible); } //菜单绘制 popupMenuHelper.Prepare(CreateGraphics()); Width=popupMenuHelper.Width; Height=popupMenuHelper.Height; } //////绘制 /// ////// privatevoidPopupMenuControl_Paint(objectsender,PaintEventArgse) { popupMenuHelper.Draw(e.Graphics); } /// ///鼠标移过 /// ////// privatevoidPopupMenuControl_MouseMove(objectsender,MouseEventArgse) { if(popupMenuHelper.IsMouseMove(e.X,e.Y)) { popupMenuHelper.Draw(CreateGraphics()); } } /// ///鼠标按下 /// ////// privatevoidPopupMenuControl_MouseDown(objectsender,MouseEventArgse) { if(popupMenuHelper.IsMouseDown(e.X,e.Y)) { inthitIndex=popupMenuHelper.HitIndex; if(hitIndex!=-1) { boolisChecked=popupMenuHelper.IsCheckedChange(hitIndex,CreateGraphics()); OnCheckedChanged(hitIndex,isChecked); } } } /// ///勾选改变 /// ////// publicvirtualvoidOnCheckedChanged(inthitIndex,boolisChecked) { CheckedChangedEvent?.Invoke(hitIndex,isChecked); } }
4、这上面涉及到一个PopupMenuHelper的帮助类,此帮助类主要是为PopupMenuControl控件实现菜单绘制的功能,其代码如下:
classPopupMenuHelper { //变量 privatePopupMenuItemhotItem=null;//当前Item privateListitems=newList ();//Item集合 privateBitmapbitmap;//位图 privateGraphicsgraphics;//图像 privatestaticreadonlyintBasicConst=24;//Item:高度、Image宽度 privatestaticreadonlyintBasicGap=3;//四周间距 privatestaticreadonlyintBasicRows=3;//最大行数 privatestaticreadonlyintBasicSide=10;//Item:CheckBox边长(建议用偶数) privateinttotality=1;//分割总数 privateint[]eachWidth=null;//各个宽度 //属性 publicintWidth{get{returnbitmap.Width;}}//宽度 publicintHeight{get{returnbitmap.Height;}}//高度 //PopupMenuItem类 privateclassPopupMenuItem { //属性 publicstringItemText{get;set;}//Item文本 publicboolIsChecked{get;set;}//勾选状态 //构造函数 publicPopupMenuItem(stringitemText):this(itemText,false) { } publicPopupMenuItem(stringitemText,boolisChecked) { ItemText=itemText; IsChecked=isChecked; } } //无参构造函数 publicPopupMenuHelper() { } /// ///被点击Item的Index /// publicintHitIndex { get { returnitems.IndexOf(hotItem); } } //////勾选改变状态 /// ///被点击Item的Index /// 图像 /// publicboolIsCheckedChange(inthitIndex,Graphicsg) { items[hitIndex].IsChecked=!items[hitIndex].IsChecked; Draw(g); returnitems[hitIndex].IsChecked; } /// ///添加Item /// ///Item文本 /// Item勾选状态 publicvoidAddItem(stringitemText,boolisChecked) { items.Add(newPopupMenuItem(itemText,isChecked)); } /// ///绘制菜单准备 /// ///图像 publicvoidPrepare(Graphicsg) { //获取菜单的宽度及高度 totality=(int)Math.Ceiling((double)items.Count/BasicRows); eachWidth=newint[totality]; inttotalWidth=0,totalHeight=0; doublemaxTextWidth=0; if(totality==1) { totalHeight=items.Count*BasicConst+2*BasicGap; foreach(PopupMenuItemiteminitems) { //SizeF:存储有序浮点数对,通常为矩形的宽度和高度。 SizeFsizeF=g.MeasureString(item.ItemText,SystemInformation.MenuFont); maxTextWidth=Math.Max(maxTextWidth,sizeF.Width); } totalWidth=(int)Math.Ceiling((double)maxTextWidth)+BasicConst+2*BasicGap; eachWidth[0]=(int)Math.Ceiling((double)maxTextWidth)+BasicConst; } else { totalHeight=BasicRows*BasicConst+2*BasicGap; introws=0,cols=1; foreach(PopupMenuItemiteminitems) { rows++; //SizeF:存储有序浮点数对,通常为矩形的宽度和高度。 SizeFsizeF=g.MeasureString(item.ItemText,SystemInformation.MenuFont); maxTextWidth=Math.Max(maxTextWidth,sizeF.Width); if(cols ///绘制菜单 /// /// publicvoidDraw(Graphicsg) { Rectanglearea=newRectangle(0,0,bitmap.Width,bitmap.Height); graphics.Clear(SystemColors.Menu); DrawBackground(graphics,area); DrawItems(graphics); g.DrawImage(bitmap,area,area,GraphicsUnit.Pixel); } /// ///绘制菜单背景 /// ////// privatevoidDrawBackground(Graphicsg,Rectanglearea) { //描边 using(PenborderPen=newPen(Color.FromArgb(112,112,112))) g.DrawRectangle(borderPen,area); //Image及Text intleft=BasicGap,top=BasicGap; if(totality==1) { RectangleimageArea=newRectangle(left,top,BasicConst,items.Count*BasicConst); using(BrushbackBrush=newSolidBrush(Color.FromArgb(240,240,240))) g.FillRectangle(backBrush,imageArea); RectangletextArea=newRectangle(left+BasicConst,top,eachWidth[0],items.Count*BasicConst); using(BrushbackBrush=newSolidBrush(Color.FromArgb(255,255,255))) g.FillRectangle(backBrush,textArea); } else { for(inti=0;i ///绘制所有菜单Item /// /// 图像 privatevoidDrawItems(Graphicsg) { intleft=BasicGap,top=BasicGap; introws=0,cols=1; foreach(PopupMenuItemiteminitems) { if(totality==1) { DrawSingleItem(g,left,reftop,eachWidth[0],item,item==hotItem); } else { rows++; DrawSingleItem(g,left,reftop,eachWidth[cols-1],item,item==hotItem); //1..[totality-1]列 if(rows%BasicRows==0) { left+=eachWidth[cols-1]; top=BasicGap; cols++; rows=0; } } } } /// ///绘制单个菜单Item /// ///图像 /// 图像Top /// 菜单Item /// 是否为当前菜单Item privatevoidDrawSingleItem(Graphicsg,intleft,refinttop,intwidth,PopupMenuItemitem,boolisHotItem) { //Item区域 RectangledrawRect=newRectangle(left,top,width,BasicConst); top+=BasicConst; //Text区域 RectangleitemTextArea=newRectangle ( drawRect.Left+BasicConst, drawRect.Top, drawRect.Width-BasicConst, drawRect.Height ); //背景色及描边色 if(isHotItem) { //HotItem RectanglehotItemArea=newRectangle(drawRect.Left,drawRect.Top,drawRect.Width,drawRect.Height); using(SolidBrushbackBrush=newSolidBrush(Color.FromArgb(214,235,255))) g.FillRectangle(backBrush,hotItemArea); using(PenborderPen=newPen(Color.FromArgb(51,153,255))) g.DrawRectangle(borderPen,hotItemArea); } //Text处理 StringFormatitemTextFormat=newStringFormat(); //NoClip:允许显示字形符号的伸出部分和延伸到矩形外的未换行文本。 //NoWrap:在矩形内设置格式时,禁用自动换行功能。 itemTextFormat.FormatFlags=StringFormatFlags.NoClip|StringFormatFlags.NoWrap; //Near:指定文本靠近布局对齐。 itemTextFormat.Alignment=StringAlignment.Near; //Center:指定文本在布局矩形中居中对齐(呃,感觉不是很垂直居中,偏上了一些)。 itemTextFormat.LineAlignment=StringAlignment.Center; //Show:显示热键前缀。 itemTextFormat.HotkeyPrefix=HotkeyPrefix.Show; SolidBrushtextBrush=newSolidBrush(SystemColors.MenuText); g.DrawString(item.ItemText,SystemInformation.MenuFont,textBrush,itemTextArea,itemTextFormat); //Checkbox处理 if(item.IsChecked) { intcheckBoxGap=(int)((drawRect.Height-BasicSide)/2); intcheckBoxLeft=drawRect.Left+checkBoxGap; intcheckBoxTop=drawRect.Top+checkBoxGap; //将checkBoxArea的Top减1,与文本的对齐效果稍微好一些。 RectanglecheckBoxArea=newRectangle(checkBoxLeft,checkBoxTop-1,BasicSide,BasicSide); using(BrushcheckBoxBrush=newSolidBrush(Color.FromArgb(214,235,255))) g.FillRectangle(checkBoxBrush,checkBoxArea); using(PencheckBoxPen=newPen(Color.FromArgb(51,153,255))) g.DrawRectangle(checkBoxPen,checkBoxArea); using(PencheckBoxTick=newPen(Color.FromArgb(51,153,255))) { g.DrawLine(checkBoxTick,newPoint(checkBoxLeft,checkBoxTop-1+(int)(BasicSide/2)),newPoint(checkBoxLeft+(int)(BasicSide/2),checkBoxTop-1+BasicSide)); g.DrawLine(checkBoxTick,newPoint(checkBoxLeft+(int)(BasicSide/2),checkBoxTop-1+BasicSide),newPoint(checkBoxLeft+BasicSide+BasicGap,checkBoxTop-1-BasicGap)); } } } /// ///点击测试 /// ///X坐标 /// Y坐标 /// privatePopupMenuItemHitTest(intX,intY) { if(X<0||X>Width||Y<0||Y>Height) { returnnull; } intleft=BasicGap,top=BasicGap; introws=0,cols=1; foreach(PopupMenuItemiteminitems) { if(totality==1) { rows++; if(X>left&&X top+(rows-1)*BasicConst&&Y left&&X top+(rows-1)*BasicConst&&Y ///是否是鼠标移过 /// /// X坐标 /// Y坐标 /// publicboolIsMouseMove(intX,intY) { PopupMenuItempopupMenuItem=HitTest(X,Y); if(popupMenuItem!=hotItem) { hotItem=popupMenuItem; returntrue; } else { returnfalse; } } /// ///是否是鼠标按下 /// ///X坐标 /// Y坐标 /// publicboolIsMouseDown(intX,intY) { PopupMenuItempopupMenuItem=HitTest(X,Y); returnpopupMenuItem!=null; } }
这个类实现了多菜单页面的功能:即如果DataGridView字段非常的多,可通过产生多列菜单来显示,程序是通过BasicRows变量来控制。
5、新建一个DataGridViewColumnSelector类,此类的功能主要是衔接DataGridView与PopupMenuControl,其代码如下:
//////DataGridView右键菜单自定义显示及隐藏列 /// classDataGridViewColumnSelector { privateDataGridViewdgvTarget=null;//待处理的DataGridView对象 privateToolStripDropDowndropDown;//用于加载PopupMenu控件 PopupMenuControlpopupMenuControl=newPopupMenuControl();//PopupMenu控件 //无参构造函数 publicDataGridViewColumnSelector() { //注册PopupMenu控件事件 popupMenuControl.CheckedChangedEvent+=newPopupMenuControl.CheckedChanged(OnCheckedChanged); //使用容器承载PopupMenu控件(相当于容器类型的ToolStripItem) ToolStripControlHostcontrolHost=newToolStripControlHost(popupMenuControl); controlHost.Padding=Padding.Empty; controlHost.Margin=Padding.Empty; controlHost.AutoSize=false; //加载PopupMenu控件 dropDown=newToolStripDropDown(); dropDown.Padding=Padding.Empty; dropDown.AutoClose=true; dropDown.Items.Add(controlHost); } //有参构造函数 publicDataGridViewColumnSelector(DataGridViewdataGridView):this() { DataGridView=dataGridView; } //DataGridView属性 publicDataGridViewDataGridView { get{returndgvTarget;} set { //去除单元格点击事件 if(dgvTarget!=null){dgvTarget.CellMouseClick-=newDataGridViewCellMouseEventHandler(DataGridView_CellMouseClick);} dgvTarget=value; //注册单元格点击事件 if(dgvTarget!=null){dgvTarget.CellMouseClick+=newDataGridViewCellMouseEventHandler(DataGridView_CellMouseClick);} } } //////右键点击标题栏弹出菜单 /// ////// privatevoidDataGridView_CellMouseClick(objectsender,DataGridViewCellMouseEventArgse) { if(e.Button==MouseButtons.Right&&e.RowIndex==-1) { popupMenuControl.Initialize(dgvTarget); //将菜单显示在光标位置 dropDown.Show(Cursor.Position); } } /// ///勾选事件执行方法 /// ////// privatevoidOnCheckedChanged(inthitIndex,boolisChecked) { dgvTarget.Columns[hitIndex].Visible=isChecked; } }
6、以上这些,已经实现了全部的功能。下面开始建一个WinForm程序来测试结果,为方便测试将DataGridView的数据源由xml文件读取。
从SQLServer数据库随便找张数据表生成XML,文件保存为Test.xml。(请将Test.xml文件拷贝到Debug文件夹下面)
SELECTTOP10MO_NO,MRP_NO,QTY,BIL_NO FROMMF_MO WHEREMO_DD='2019-11-07' ORDERBYMO_NO FORXMLPATH('Category'),TYPE,ROOT('DocumentElement')
7、新建一个WinForm程序,命名为Main,并拖入一个DataGridView控件,Main_Load方法如下:
privatevoidMain_Load(objectsender,EventArgse) { try { //xml文件路径 stringpath=@"Test.xml"; //读取文件 DataSetds=newDataSet(); if(File.Exists(path)) { ds.ReadXml(path); } dataGridView1.DataSource=ds.Tables.Count>0?ds.Tables[0]:null; //加工dataGridView1 #region加列标题测试 dataGridView1.Columns[0].HeaderText="制令单号"; dataGridView1.Columns[1].HeaderText="成品编号"; dataGridView1.Columns[2].HeaderText="生产数量"; dataGridView1.Columns[3].HeaderText="来源单号"; #endregion DataGridViewColumnSelectorcolumnSelector=newDataGridViewColumnSelector(dataGridView1); } catch(Exceptionex) { MessageBox.Show(ex.Message,"提示",MessageBoxButtons.OK,MessageBoxIcon.Information); } }
8、执行程序,在任意DataGridView标题栏右击,即可弹出菜单:
总结
以上所述是小编给大家介绍的DataGridView右键菜单自定义显示及隐藏列功能,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对毛票票网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。