[英]How do I correctly position a Context Menu when I right click a DataGridView's column header?
I would like to extended DataGridView to add a second ContextMenu which to select what columns are visible in the gird.我想扩展 DataGridView 以添加第二个 ContextMenu 以选择网格中可见的列。 The new ContextMenu will be displayed on right click of a column's header.
新的 ContextMenu 将在列标题上单击鼠标右键显示。
I am having difficulty get the correct horizontal position to show the context menu.我很难获得正确的水平位置来显示上下文菜单。 How can I correct this?
我该如何纠正?
public partial class Form1 : Form
{
DataGridView dataGrid;
ContextMenuStrip contextMenuStrip;
public Form1()
{
InitializeComponent();
dataGrid = new DataGridView();
Controls.Add(dataGrid);
dataGrid.Dock = System.Windows.Forms.DockStyle.Fill;
dataGrid.ColumnHeaderMouseClick += new System.Windows.Forms.DataGridViewCellMouseEventHandler(ColumnHeaderMouseClick);
dataGrid.DataSource = new Dictionary<string, string>().ToList();
contextMenuStrip = new ContextMenuStrip();
contextMenuStrip.Items.Add("foo");
contextMenuStrip.Items.Add("bar");
}
private void ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Right)
{
contextMenuStrip.Show(PointToScreen(e.Location));
}
}
}
Here is a very simple way to make context menu appear where you right-click it.这是使上下文菜单出现在您右键单击它的位置的一种非常简单的方法。
Handle the event ColumnHeaderMouseClick处理ColumnHeaderMouseClick事件
private void grid_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Right)
contextMenuHeader.Show(Cursor.Position);
}
contextMenuHeader
is a ContextMenuStrip
that can be defined in the Designer view or at runtime. contextMenuHeader
是一个ContextMenuStrip
,可以在设计器视图中或在运行时定义。
要获得鼠标光标的坐标,您可以这样做。
ContextMenu.Show(this, myDataGridView.PointToClient(Cursor.Position));
Have you tried using the Show overload that accepts a control and a position?您是否尝试过使用接受控件和位置的 Show 重载?
For example:例如:
contextMenuStrip.Show(dataGrid, e.Location);
Edit: Full example编辑:完整示例
public partial class Form1 : Form
{
DataGridView dataGrid;
ContextMenuStrip contextMenuStrip;
public Form1()
{
InitializeComponent();
dataGrid = new DataGridView();
Controls.Add(dataGrid);
dataGrid.Dock = System.Windows.Forms.DockStyle.Fill;
dataGrid.MouseDown += MouseDown;
dataGrid.DataSource = new Dictionary<string, string>().ToList();
contextMenuStrip = new ContextMenuStrip();
contextMenuStrip.Items.Add("foo");
contextMenuStrip.Items.Add("bar");
}
private void MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Right)
{
if (dataGrid.HitTest(e.X, e.Y).Type == DataGridViewHitTestType.ColumnHeader)
{
contextMenuStrip.Show(dataGrid, e.Location);
}
}
}
}
The position returned is relative to the cell.返回的位置是相对于单元格的。 So we have to add that offset.
所以我们必须添加该偏移量。
private void grdView_CellMouseClick(object sender, DataGridViewCellMouseEventArgs e)
{
if (e.Button == MouseButtons.Right)
{
var pos = ((DataGridView)sender).GetCellDisplayRectangle(e.ColumnIndex,
e.RowIndex, false).Location;
pos.X += e.X;
pos.Y += e.Y;
contextMenuStrip.Show((DataGridView)sender,pos);
}
}
e.Location
does not show the popup menu at the correct coordinates, instead just use the MousePosition
property as follows: e.Location
不会在正确的坐标处显示弹出菜单,而是使用MousePosition
属性,如下所示:
ContextMenuStrip.Show(MousePosition)
or, explicitely或者,明确地
ContextMenuStrip.Show(Control.MousePosition)
You were nearly right.你几乎是对的。 You just need to the apply the
PointToScreen
method to the calling control:您只需要将
PointToScreen
方法应用于调用控件:
private void ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Right)
{
contextMenuStrip.Show(((DataGridView)sender).PointToScreen(e.Location));
}
}
I think this is the most elegant solution, because it uses only the ColumnHeaderMouseClick
arguments and not Cursor.Position
.我觉得这是最优雅的解决方案,因为它仅使用
ColumnHeaderMouseClick
论据,而不是Cursor.Position
。
Calling Show
twice will get you the exact location of the cursor.调用
Show
两次将为您提供光标的确切位置。 This answer is for those whom are unable to get the result with all above answers.此答案适用于无法通过上述所有答案获得结果的人。
private void MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Right)
{
contextMenuStrip.Show(dataGrid, e.Location));
contextMenuStrip.Show(Cursor.Position);
}
}
最后这对我有用。
ContextMenu.Show(myDataGridView, myDataGridView.PointToClient(Cursor.Position));
Where I was going wrong was that DataGridViewCellMouseEventArgs returns the location/x,y of where the mouse clicked within the column header.我出错的地方是 DataGridViewCellMouseEventArgs 返回鼠标在列标题内单击的位置/x,y。 Instead I need to use HitTest in the grid's MouseDown event for a hit on the column headers and then convert the position of the hit from the gird co-ordinates to the screen co-ordinates.
相反,我需要在网格的 MouseDown 事件中使用 HitTest 来点击列标题,然后将点击的位置从网格坐标转换为屏幕坐标。
public partial class Form1 : Form
{
DataGridView dataGrid;
ContextMenuStrip contextMenuStrip;
public Form1()
{
InitializeComponent();
dataGrid = new DataGridView();
Controls.Add(dataGrid);
dataGrid.Dock = System.Windows.Forms.DockStyle.Fill;
//dataGrid.ColumnHeaderMouseClick += ColumnHeaderMouseClick;
dataGrid.MouseDown += MouseDown;
dataGrid.DataSource = new Dictionary<string, string>().ToList();
contextMenuStrip = new ContextMenuStrip();
contextMenuStrip.Items.Add("foo");
contextMenuStrip.Items.Add("bar");
}
private void ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Right)
{
contextMenuStrip.Show(PointToScreen(e.Location));
}
}
private void MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Right)
{
if (dataGrid.HitTest(e.X, e.Y).Type == DataGridViewHitTestType.ColumnHeader)
{
contextMenuStrip.Show(dataGrid.PointToScreen(e.Location));
}
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.