8
votes

In my application I have a DataGridView that is meant for configuring some options. The idea is that you can enter whatever text you want in the first column, but if you right click it will give you explicitly supported values. I need this to be a textbox rather than a dropdown list because I need to support editing invalid (or old) configurations.

What I want is the user to right click in the field name column and have a context menu that is valid based on what type of configuration this is. Therefore, I coded the following event

    private void grvFieldData_CellMouseClick(object sender, DataGridViewCellMouseEventArgs e)
    {
        // If this is a right click on the Field name column, create a context menu 
        //   with recognized options for that field
        if (e.Button == MouseButtons.Right && grvFieldData.Columns[e.ColumnIndex].Name == "clmFieldName")
        {
            ContextMenu menu = new ContextMenu();

            if (_supportedDataGrids.ContainsKey((cmbDataGrid.SelectedItem as DataGridFieldList).GridName))
            {
                // Loop through all the fields and add them to the context menu
                List<string> fields = _supportedDataGrids[((cmbDataGrid.SelectedItem as DataGridFieldList).GridName)];
                fields.Sort();

                foreach (string field in fields)
                    menu.MenuItems.Add(new MenuItem(field));

                // Make sure there is at least one field before displaying the context menu
                if (menu.MenuItems.Count > 0)
                    menu.Show(this, e.Location, LeftRightAlignment.Right);
            }
        }
    }

This works "correctly", but the context menu is appearing at the top of the form, not where the mouse pointer is. If I change the Show() call to use the DataGridView instead of the form, I have the same issue but instead it appears at the top-left hand corner of the grid, not where the mouse is.

Oddly enough, if I change this event to a MouseClick event (instead of a CellMouseclick event) everything works and the context menu appears exactly where the mouse pointer is. The problem with this option is that the user might not be right clicking on the cell that is currently selected, which means that when they click on a menu item, the selected cell will be changed and not the cell they right clicked on.

Does anyone have any hints why context menus created with the CellMouseClick are not showing at the correct spot?

5

5 Answers

18
votes
 menu.Show(this, e.Location, LeftRightAlignment.Right);

The 2nd argument is the mouse location, relative to the cell's upper left corner. As programmed, you make that offset relative from this, the form, which will make the menu appear in the upper left corner of the form. Use the DGV as the 1st argument doesn't work either, now it is in the upper left corner of the grid.

A couple of ways to fix this, but this is the easy way:

 Point pos = this.PointToClient(Cursor.Position);
 menu.Show(this, pos, LeftRightAlignment.Right);

You can arbitrarily replace this with grvFieldData.

3
votes

In the datagridview mouse click event:

if e.button= mousebutton.right 
{
   contextmenu1.Show(MousePosition);
}
1
votes

try to use PointToClient to get proper spot

1
votes

It's not showing in the correct spot because e.Location is the location relative to the parent object's top-left corner, which in this case is the cell itself. Location properties are always relative to their container.

To get the position of the mouse cursor relative to the top-left of the form itself, you can use

this.PointToClient(Cursor.Position);
1
votes

I have solved this problem... ones could find this method strange, but it works fine !) If we want to see a context menu while pressing right mouse btn in the datagridview cell, and right there, not in the middle of the screen or somewhere else, we need to:

make some variables

int x=0;
int y=0;

make an 'MouseMove' Event for datagridview1 lke that:

private void dataGridView1_MouseMove(object sender, MouseEventArgs e)
{
   x = e.X;
   y = e.Y;
}

and

private void dataGridView1_CellMouseClick(object sender, DataGridViewCellMouseEventArgs e)
{
   if (e.Button == System.Windows.Forms.MouseButtons.Right)
   {
      contextMenuStrip1.Show(dataGridView1, x,y);
   }
}

your welcome