2011-11-20 16 views
28

Me gustaría ampliar DataGridView para agregar un segundo ContextMenu que seleccione qué columnas son visibles en el ceñidor. El nuevo ContextMenu se mostrará al hacer clic derecho en el encabezado de una columna.¿Cómo coloco correctamente un menú contextual cuando hago clic con el botón derecho en el encabezado de columna de DataGridView?

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

Respuesta

1

donde iba mal fue que DataGridViewCellMouseEventArgs devuelve la ubicación/x, y de donde está el ratón hace clic dentro la columna encabezamiento. En cambio, necesito usar HitTest en el evento MouseDown de la grilla para dar un golpe en los encabezados de las columnas y luego convertir la posición del golpe de las coordenadas de la cejilla a las coordenadas de la 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)); 
      } 
     } 
    } 
} 
8

¿Ha intentado utilizar la función Show overload que acepta un control y una posición?

Por ejemplo:

contextMenuStrip.Show(dataGrid, e.Location); 

Editar: 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); 
      } 
     } 
    } 
} 
+0

El menú de contenido aparece en la esquina superior izquierda de la pantalla, ya que e.location es la posición del mouse dentro del encabezado de la columna. Ya resolví el problema, pero gracias por ayudarme. –

+0

De acuerdo con su respuesta a su pregunta, la ubicación de e está dentro de la cuadrícula de datos, no del encabezado, así que competente_tech estaba correcto. –

+0

Parece que probé mal la respuesta de competente_tech y de hecho es correcto si se usa dentro del evento MouseDown. –

65

Aquí hay una manera muy simple de hacer que el menú contextual aparezca al hacer clic con el botón derecho.

controlar 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.

+3

Esta debería ser la respuesta aceptada. – Askolein

+3

+1: La parte relevante para mí fue Cursor.Position (ahora me siento tonto) – NobodysNightmare

+0

Simple pero potente –

13

Para obtener la coordenada del cursor del mouse, puede hacerlo.

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

Esto es correcto. La respuesta aceptada no compila. – icanbenchurcat

3

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

ContextMenuStrip.Show(MousePosition) 

o, explícitamente

ContextMenuStrip.Show(Control.MousePosition) 
0

Eras casi derecha. Sólo tiene que 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 sólo utiliza los argumentos y no ColumnHeaderMouseClickCursor.Position.

2

La posición devuelta es relativa a la celda. Entonces tenemos que agregar esa compensación.

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