开发者社区> 老朱教授> 正文
阿里云
为了无法计算的价值
打开APP
阿里云APP内打开

winfrom编程实现DataGridView关联快捷菜单

简介:
+关注继续查看

在winfrom编程中我们经常使用表格控件DataGridView的行关联快捷菜单(也称为上下文弹出菜单)ContextMenuStrip,基本步骤如下:

在窗体上设计ContextMenuStrip快捷菜单控件;
设置DataGridView.RowTemplate.ContextMenuStrip属性为指定的快捷菜单;
在菜单弹出前捕获关联事件DataGridView.RowContextMenuStripNeeded,获得当前行与快捷菜单,并做适当处理。
但是,使用其关联事件DataGridView.RowContextMenuStripNeeded有一个重要的前提:“RowContextMenuStripNeeded 事件仅在设置了DataGridView控件的DataSource属性或者该控件的VirtualMode属性为 true 时发生。”(参考MSDN:RowContextMenuStripNeeded 事件)。

此外,上述方法还有一个不足之处:在非数据行的地方(如:表格列头或行头)不能使用RowTemplate.ContextMenuStrip快捷菜单,也捕获不到事件DataGridView.RowContextMenuStripNeeded事件。

事实上,DataGridView.ContextMenuStrip是控件本身的快捷菜单。本文介绍的定制DataGridView控件,就是直接应用其ContextMenuStrip属性,定制一个快捷菜单关联事件,实现RowTemplate.ContextMenuStrip类似功能。基本思路如下:

重写DataGridView.MouseDown(MouseEventArgs e)方法,捕获鼠标右击事件;
根据事件参数MouseEventArgs的鼠标位置,计算DataGridView当前位置的行号与列号;
定制关联事件ContextMenuStripMenu,在快捷菜单弹出前获取行号、列号与快捷菜单对象对象。


关键技术
捕获鼠标右击位置(坐标),根据该位置计算当前行号与列号,并引发自定义关联事件。如下代码是捕获鼠标右击事件(定制DataGridView控件中的代码):
protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown(e);
if (e.Button == MouseButtons.Right)
{
if (this.ContextMenuStrip != null && this.ContextMenuStripNeeded != null)
{
int rowIndex = this.GetRowIndexAt(e.Location); // 计算行号
int colIndex = this.GetColIndexAt(e.Location); // 计算列号
ContextMenuStripNeededEventArgs ee; // 事件参数
ee = new ContextMenuStripNeededEventArgs(this.ContextMenuStrip, rowIndex, colIndex);
this.OnContextMenuStripNeeded(ee); // 引发自定义事件,执行事件方法
}
}
}
protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown(e);
if (e.Button == MouseButtons.Right)
{
if (this.ContextMenuStrip != null && this.ContextMenuStripNeeded != null)
{
int rowIndex = this.GetRowIndexAt(e.Location); // 计算行号
int colIndex = this.GetColIndexAt(e.Location); // 计算列号
ContextMenuStripNeededEventArgs ee; // 事件参数
ee = new ContextMenuStripNeededEventArgs(this.ContextMenuStrip, rowIndex, colIndex);
this.OnContextMenuStripNeeded(ee); // 引发自定义事件,执行事件方法
}
}
}


只有在ContextMenuStrip属性对象非空,以及定制关联事件ContextMenuStripNeeded非空(即有事件注册者)时,才需要计算行列坐标,并由OnContextMenuStripNeeded引发调用事件处理方法。当前鼠标位置的行/列编号计算方法如下:


private int GetColIndexAt(Point mouseLocation)
{
int colIndex = -1;
int colOffset = 0;
int gridWidth = 1;
int padding = 1;
if (this.RowHeadersVisible)
{
colOffset += this.RowHeadersWidth;
padding = 0;
}
if (colOffset + padding < mouseLocation.X) // 超过表列头的范围(不含顶头的边框)
{
int curCol = this.FirstDisplayedScrollingColumnIndex;
for (int k = 0; k <= this.DisplayedColumnCount(true); k++)
{
if (curCol >= this.Columns.Count)
{
break;
}
if (this.Columns[curCol].Visible)
{
colOffset += this.Columns[curCol].Width;
}
if (colOffset + padding + gridWidth > mouseLocation.X) // x为当前边框位置
{
colIndex = curCol;
break;
}
curCol++;
}
}
return colIndex;
}
private int GetRowIndexAt(Point mouseLocation)
{
int rowIndex = -1;
int rowOffset = 0;
int gridWidth = 1;
int padding = 1;
if (this.ColumnHeadersVisible)
{
rowOffset += this.ColumnHeadersHeight;
padding = 0;
}
if (rowOffset + padding < mouseLocation.Y) // 超过表列头的范围(不含顶头的边框)
{
int curRow = this.FirstDisplayedScrollingRowIndex;
for (int k = 0; k <= this.DisplayedRowCount(true); k++)
{
if (curRow >= this.Rows.Count)
{
break;
}
if (this.Rows[curRow].Visible)
{
rowOffset += this.Rows[curRow].Height;
}
if (rowOffset + padding + gridWidth > mouseLocation.Y) // y为当前边框位置
{
rowIndex = curRow;
break;
}
curRow++;
}
}
return rowIndex;
}
private int GetColIndexAt(Point mouseLocation)
{
int colIndex = -1;
int colOffset = 0;
int gridWidth = 1;
int padding = 1;
if (this.RowHeadersVisible)
{
colOffset += this.RowHeadersWidth;
padding = 0;
}
if (colOffset + padding < mouseLocation.X) // 超过表列头的范围(不含顶头的边框)
{
int curCol = this.FirstDisplayedScrollingColumnIndex;
for (int k = 0; k <= this.DisplayedColumnCount(true); k++)
{
if (curCol >= this.Columns.Count)
{
break;
}
if (this.Columns[curCol].Visible)
{
colOffset += this.Columns[curCol].Width;
}
if (colOffset + padding + gridWidth > mouseLocation.X) // x为当前边框位置
{
colIndex = curCol;
break;
}
curCol++;
}
}
return colIndex;
}
private int GetRowIndexAt(Point mouseLocation)
{
int rowIndex = -1;
int rowOffset = 0;
int gridWidth = 1;
int padding = 1;
if (this.ColumnHeadersVisible)
{
rowOffset += this.ColumnHeadersHeight;
padding = 0;
}
if (rowOffset + padding < mouseLocation.Y) // 超过表列头的范围(不含顶头的边框)
{
int curRow = this.FirstDisplayedScrollingRowIndex;
for (int k = 0; k <= this.DisplayedRowCount(true); k++)
{
if (curRow >= this.Rows.Count)
{
break;
}
if (this.Rows[curRow].Visible)
{
rowOffset += this.Rows[curRow].Height;
}
if (rowOffset + padding + gridWidth > mouseLocation.Y) // y为当前边框位置
{
rowIndex = curRow;
break;
}
curRow++;
}
}
return rowIndex;
}


代码中,参数mouseLocation来自MouseEventArgs的Location属性,this.FirstDisplayedScrollingRowIndex表示当前显示的第一行的行号,this.DisplayedRowCount(true)获取显示的全部行数,参数true表示要包括最后部分显示的行。

按照惯例,-1表示当前鼠标位置位于所有行或列之外,如:表的列头、行头等地方。




本文转自94cool博客园博客,原文链接:http://www.cnblogs.com/94cool/archive/2009/09/09/1563030.html,如需转载请自行联系原作者


版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
C#编程-77:DataGridView绘制行序号
C#编程-77:DataGridView绘制行序号
4 0
Android - 安卓设备在微信中播放视频结束后出现广告的解决办法
Android - 安卓设备在微信中播放视频结束后出现广告的解决办法
33 0
C#编程-79:DataGridView分页显示
C#编程-79:DataGridView分页显示
91 0
《机器人编程实战》一一2.4 下文预告
本节书摘来自华章出版社《机器人编程实战》一 书中的第2章,第2.4节,作者:[美]卡梅伦·休斯(Cameron Hughes) 特雷西·休斯(Tracey Hughes)著 ,更多章节内容可以访问云栖社区“华章计算机”公众号查看。
926 0
《机器人编程实战》一一3.4 下文预告
本节书摘来自华章出版社《机器人编程实战》一 书中的第3章,第3.4节,作者:[美]卡梅伦·休斯(Cameron Hughes) 特雷西·休斯(Tracey Hughes)著 ,更多章节内容可以访问云栖社区“华章计算机”公众号查看。
911 0
Android 仿照微信发说说,既能实现拍照,选图库,多图案上传 使用Retrofit2.0技术
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u010046908/article/details/50767904          最近项目做完了,有闲暇时间,一直想做一个类似微信中微信发说说,既能实现拍照,选图库,多图案上传的案例,目前好多App都有类似微信朋友圈的功能,能过发表说说等附带图片上传。
855 0
Datagridview列首右键弹出隐藏列菜单
在Winform中右键弹出Datagridview显示列菜单已经有很多人做了,参看下面链接. http://www.codeproject.com/KB/grid/DGVColumnSelector.
810 0
+关注
3545
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
低代码开发师(初级)实战教程
立即下载
阿里巴巴DevOps 最佳实践手册
立即下载
冬季实战营第三期:MySQL数据库进阶实战
立即下载