Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I correctly position a Context Menu when I right click a DataGridView's column header?

Tags:

c#

.net

winforms

I would like to extended DataGridView to add a second ContextMenu which to select what columns are visible in the gird. The new ContextMenu will be displayed on right click of a column's header.

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));
        }
    }
}
like image 233
Adrian Toman Avatar asked Nov 20 '11 02:11

Adrian Toman


4 Answers

Here is a very simple way to make context menu appear where you right-click it.

Handle the event 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.

like image 187
Zyo Avatar answered Oct 08 '22 18:10

Zyo


To get the coordinate of the mouse cursor you could do this.

ContextMenu.Show(this, myDataGridView.PointToClient(Cursor.Position)); 
like image 21
Microsoft Developer Avatar answered Oct 08 '22 18:10

Microsoft Developer


Have you tried using the Show overload that accepts a control and a position?

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);
            }
        }
    }
}
like image 10
competent_tech Avatar answered Oct 08 '22 17:10

competent_tech


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);
        }
    }
like image 6
David Avatar answered Oct 08 '22 18:10

David