2011-11-20 17 views
28

我想擴展DataGridView添加第二個ContextMenu來選擇哪些列在網格中可見。新的ContextMenu將顯示在列標題的右鍵上。當我右鍵單擊DataGridView的列標題時,如何正確定位上下文菜單?

我很難得到正確的水平位置來顯示上下文菜單。我該如何解決這個問題?

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

回答

1

我要去哪裏錯了是DataGridViewCellMouseEventArgs返回在鼠標內列點擊位置/ X,Y頭。相反,我需要在網格的MouseDown事件中使用HitTest打擊列標題,然後將網格座標中的命中位置轉換爲屏幕座標。

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

您是否嘗試過使用Show overload接受控件和位置?

例如:

contextMenuStrip.Show(dataGrid, e.Location); 

編輯:完整的示例

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

內容菜單出現在屏幕的左上角,因爲e.location是列標題內的鼠標位置。我已經解決了這個問題,但感謝您的幫助。 –

+0

根據你的回答你的問題e.location是在datagrid,而不是columnheader,所以competent_tech是正確的。 –

+0

這似乎是我測試competent_tech的答案不好,他確實是正確的,如果在MouseDown事件中使用。 –

65

這是一個非常簡單的方法,使上下文菜單出現在你右鍵點擊它。

處理該事件ColumnHeaderMouseClick

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

contextMenuHeader是可以在設計器視圖或在運行時定義的ContextMenuStrip

+3

這應該是被接受的答案。 – Askolein

+3

+1:我的相關部分是Cursor.Position(現在我覺得很傻) – NobodysNightmare

+0

簡單但功能強大 –

13

要獲得鼠標光標的座標,您可以執行此操作。

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

這是正確的。接受的答案不能編譯。 – icanbenchurcat

3

e.Location不顯示在正確的座標,在彈出菜單中,而不是僅僅使用MousePosition屬性如下:

ContextMenuStrip.Show(MousePosition) 

,或者明確地

ContextMenuStrip.Show(Control.MousePosition) 
0

你是接近直角的。你只需要在該PointToScreen方法應用於呼叫控制:

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

我覺得這是最優雅的解決方案,因爲它只有ColumnHeaderMouseClick論據,而不是Cursor.Position使用。

2

返回的位置是相對於單元格。所以我們必須添加該偏移量。

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); 
     } 
    } 
相關問題