2011-11-20 4 views
28

Desidero estendere DataGridView per aggiungere un secondo ContextMenu che consente di selezionare quali colonne sono visibili nella struttura. Il nuovo ContextMenu verrà visualizzato con il tasto destro del mouse sull'intestazione di una colonna.Come posiziono correttamente un menu contestuale quando faccio clic con il pulsante destro del mouse su un'intestazione di colonna di DataGridView?

Ho difficoltà a ottenere la posizione orizzontale corretta per mostrare il menu di scelta rapida. Come posso correggere questo?

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

risposta

1

dove stavo andando male era che DataGridViewCellMouseEventArgs restituisce la posizione/x, y di dove il mouse cliccato all'interno colonna intestazione. Invece ho bisogno di usare HitTest nell'evento MouseDown della griglia per un colpo sulle intestazioni delle colonne e quindi convertire la posizione del colpo dalle coordinate gird alle coordinate dello schermo.

8

Hai provato a utilizzare il sovraccarico Mostra che accetta un controllo e una posizione?

Ad esempio:

contextMenuStrip.Show(dataGrid, e.Location); 

Edit: Esempio 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

Il menu dei contenuti viene visualizzato nell'angolo in alto a sinistra dello schermo, poiché e.location è la posizione del mouse all'interno dell'intestazione della colonna. Ho risolto il problema ora ma grazie per l'aiuto. –

+0

In base alla tua risposta alla tua domanda e.location è all'interno di datagrid, non di columnheader, quindi competent_tech era corretto. –

+0

Sembrerebbe che abbia provato male la risposta competente_tech e che sia effettivamente corretto se usato all'interno dell'evento MouseDown. –

65

Ecco un modo molto semplice per visualizzare il menu di scelta rapida in cui si fa clic con il pulsante destro del mouse.

gestire l'evento ColumnHeaderMouseClick

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

contextMenuHeader è un ContextMenuStrip che può essere definito nella visualizzazione di progettazione o in fase di esecuzione.

+3

Questa dovrebbe essere la risposta accettata. – Askolein

+3

+1: La parte rilevante per me era Cursor.Position (ora mi sento stupido) – NobodysNightmare

+0

Semplice ma potente –

13

Per ottenere le coordinate del cursore del mouse, è possibile farlo.

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

Questo è corretto. La risposta accettata non viene compilata. – icanbenchurcat

3

e.Location non mostra il menu a comparsa alle coordinate corrette, invece basta utilizzare la proprietà MousePosition come segue:

ContextMenuStrip.Show(MousePosition) 

o, esplicitamente

ContextMenuStrip.Show(Control.MousePosition) 
0

Avevi quasi ragione. Hai solo bisogno di applicare il metodo PointToScreen al controllo chiamando:

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

penso che questo sia la soluzione più elegante, perché utilizza solo i ColumnHeaderMouseClick argomenti e non Cursor.Position.

2

La posizione restituita è relativa alla cella. Quindi dobbiamo aggiungere quell'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); 
     } 
    } 
Problemi correlati