简体   繁体   English

右键单击 DataGridView 的列标题时,如何正确定位上下文菜单?

[英]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.

相关问题 如何在DataGridView上使用右键单击上下文菜单? - How can I use a right click context menu on a DataGridView? 如何在单击列 header 的 DataGridView 中对 DataBound 列进行排序? - How do I sort a DataBound column in a DataGridView on a column header click? 右键单击 datagridview 的上下文菜单 - right click context menu for datagridview 单击 DataGridView header 时如何禁用上下文菜单 - How to disable a context menu when clicking on DataGridView header 仅在运行时知道变量名称时,如何使用变量名称作为DataGridView的列标题? - How do I use variable names as a column header for DataGridView when the variable name is only known during runtime? 右键单击菜单项时如何显示上下文菜单 - How to show a Context Menu when you right click a Menu Item 在按钮中单击上下文菜单如何绑定到viewModel? - In Button Click Context Menu How do I bind to viewModel? 使用右键单击上下文菜单打开C#winform,但如何显示所选项? - C# winform opens with right-click context menu, but how do I get the selected item to show up? 如何在控制台应用程序中显示右键菜单? - How do I make the right click menu in a Console app appear? 上下文菜单未显示在发生右键单击的datagridview单元附近 - Context menu not displaying near datagridview cell where right click occurred
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM