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

Adr*_*man 33 .net c# winforms

我想扩展DataGridView以添加第二个ContextMenu,用于选择gird中可见的列.右键单击列的标题将显示新的ContextMenu.

我很难获得正确的水平位置来显示上下文菜单.我怎么能纠正这个?

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));
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Zyo*_*Zyo 79

这是一个非常简单的方法,可以在右键单击它的位置显示上下文菜单.

处理事件ColumnHeaderMouseClick

private void grid_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e) {
  if (e.Button == System.Windows.Forms.MouseButtons.Right) {
    contextMenuHeader.Show(Cursor.Position);
  }
}
Run Code Online (Sandbox Code Playgroud)

contextMenuHeaderContextMenuStrip可以在Designer视图中或在运行时定义的.


Mic*_*per 18

要获得鼠标光标的坐标,您可以执行此操作.

ContextMenu.Show(this, myDataGridView.PointToClient(Cursor.Position)); 
Run Code Online (Sandbox Code Playgroud)


com*_*ech 9

您是否尝试过使用接受控件和位置的Show重载?

例如:

contextMenuStrip.Show(dataGrid, e.Location);
Run Code Online (Sandbox Code Playgroud)

编辑:完整示例

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);
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


小智 6

e.Location不会在正确的坐标处显示弹出菜单,而是仅使用该MousePosition属性,如下所示:

ContextMenuStrip.Show(MousePosition)
Run Code Online (Sandbox Code Playgroud)

或者,明确地

ContextMenuStrip.Show(Control.MousePosition)
Run Code Online (Sandbox Code Playgroud)


小智 5

返回的位置是相对于单元格的。因此,我们必须添加该偏移量。

    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);
        }
    }
Run Code Online (Sandbox Code Playgroud)


Adr*_*man 1

我出错的地方是 DataGridViewCellMouseEventArgs 返回鼠标列标题中单击的位置/x,y。相反,我需要在网格的 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));
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)