seleccionar net fila evento derecho contextual c# .net winforms

c# - net - ¿Cómo posiciono correctamente un menú contextual cuando hago clic derecho en el encabezado de columna de DataGridView?



menu contextual datagridview c# (7)

Me gustaría extender DataGridView para agregar un segundo ContextMenu para seleccionar qué columnas son visibles en el gird. El nuevo ContextMenu se mostrará al hacer clic con el botón derecho del encabezado de una columna.

Tengo dificultades para obtener la posición horizontal correcta para mostrar el menú contextual. ¿Cómo puedo corregir esto?

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)); } } }


¿Has intentado usar la sobrecarga Mostrar que acepta un control y una posición?

Por ejemplo:

contextMenuStrip.Show(dataGrid, e.Location);

Edición: Ejemplo completo

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); } } } }


Donde me estaba yendo mal fue que DataGridViewCellMouseEventArgs devuelve la ubicación / x, y de donde el mouse hizo clic dentro del encabezado de la columna. En su lugar, necesito usar HitTest en el evento MouseDown de la cuadrícula para un golpe en los encabezados de columna y luego convertir la posición del golpe de las coordenadas gird a las coordenadas de pantalla.

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)); } } } }


Esta es una forma muy sencilla de hacer que aparezca el menú contextual donde hace clic derecho.

Manejar el evento ColumnHeaderMouseClick

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

contextMenuHeader es un ContextMenuStrip que se puede definir en la vista del Diseñador o en tiempo de ejecución.


La posición devuelta es relativa a la celda. Así que tenemos que añadir ese desplazamiento.

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); } }


Para obtener la coordenada del cursor del mouse puede hacer esto.

ContextMenu.Show(this, myDataGridView.PointToClient(Cursor.Position));


Tenías casi razón. Solo necesita aplicar el método PointToScreen al control de llamada:

private void ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e) { if (e.Button == System.Windows.Forms.MouseButtons.Right) { contextMenuStrip.Show(((DataGridView)sender).PointToScreen(e.Location)); } }

Creo que esta es la solución más elegante, ya que usa solo los argumentos ColumnHeaderMouseClick y no Cursor.Position .


e.Location no muestra el menú emergente en las coordenadas correctas, en lugar de eso, use la propiedad MousePosition siguiente manera:

ContextMenuStrip.Show(MousePosition)

o, explícitamente

ContextMenuStrip.Show(Control.MousePosition)