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语言 Perl
博途软件的基本操作,快捷操作有哪些?什么是博途视图和项目视图?
博途软件开发之初就把直观、高效、可靠作为非常重要的关键因素,持续走访了世界多数国家的工程师并着眼未来,博途软件在界面设置、窗口规划布局等多方面进行优化布置。如何快速了解博途软件的界面、操作规则是提高效率的关键环节。本节我们主要来介绍博途软件的基本操作。
博途软件的基本操作,快捷操作有哪些?什么是博途视图和项目视图?
|
Java Android开发
移动应用程序设计基础——点菜单列表实现
进一步理解Android各种控件的使用,加深控件的属性、方法的使用,熟练掌握ListView控件的使用,熟练掌握对话框的使用。 实现点菜单列表 1.1布局结构 列表布局分为两大部分,上半部分显示列表内容,底部显示所有菜品的总价; 菜品项如图所示包括 1.图片,图片格式120*120; 2.标题,居中,android:textAppearance="?android:attr/textAppearanceLarge", 3.菜品介绍内容,最多显示3行,超过部分用…表示,android:textAppearan
154 0
移动应用程序设计基础——点菜单列表实现
AppleWatch开发入门五——菜单控件的使用
AppleWatch开发入门五——菜单控件的使用
173 0
AppleWatch开发入门五——菜单控件的使用
|
SQL JavaScript 前端开发
【自然框架】之鼠标点功能现(二):表单控件的“应用”—— 代码?只写需要的!
  【自然框架】之鼠标点功能现(一):单表的增删改查(即上次5月23日活动的一个主题)【Demo、源码下载】           看了大家的回复,好像不少人误会了,我为了突出“鼠标点,功能现”,所以没有说代码,没有贴代码,这就让一些人认为我想要完全抛弃VS,自己写一个“平台”来代替,不好意思,您高估我了,我可达不到。
842 0