簡體   English   中英

右鍵單擊 DataGridView 的列標題時,如何正確定位上下文菜單?

[英]How do I correctly position a Context Menu when I right click a DataGridView's column header?

我想擴展 DataGridView 以添加第二個 ContextMenu 以選擇網格中可見的列。 新的 ContextMenu 將在列標題上單擊鼠標右鍵顯示。

我很難獲得正確的水平位置來顯示上下文菜單。 我該如何糾正?

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

這是使上下文菜單出現在您右鍵單擊它的位置的一種非常簡單的方法。

處理ColumnHeaderMouseClick事件

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

contextMenuHeader是一個ContextMenuStrip ,可以在設計器視圖中或在運行時定義。

要獲得鼠標光標的坐標,您可以這樣做。

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

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

例如:

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

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

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

e.Location不會在正確的坐標處顯示彈出菜單,而是使用MousePosition屬性,如下所示:

ContextMenuStrip.Show(MousePosition)

或者,明確地

ContextMenuStrip.Show(Control.MousePosition)

你幾乎是對的。 您只需要將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

調用Show兩次將為您提供光標的確切位置。 此答案適用於無法通過上述所有答案獲得結果的人。

private void MouseDown(object sender, MouseEventArgs e)
{
    if (e.Button == System.Windows.Forms.MouseButtons.Right)
    {
        contextMenuStrip.Show(dataGrid, e.Location));
        contextMenuStrip.Show(Cursor.Position);
    }
}

最后這對我有用。

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

我出錯的地方是 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));
            }
        }
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM