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&&Xtop+(rows-1)*BasicConst&&Yleft&&Xtop+(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(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。