Подтвердить что ты не робот

Как правильно позиционировать контекстное меню, когда я нажимаю правой кнопкой мыши заголовок столбца DataGridView?

Я хотел бы расширить 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));
        }
    }
}
4b9b3361

Ответ 1

Где я ошибался, DataGridViewCellMouseEventArgs возвращает местоположение /x, y, где мышь щелкнула внутри заголовок столбца. Вместо этого мне нужно использовать HitTest в событии MouseDown сетки для попадания в заголовки столбцов, а затем преобразовать позицию хита из координатных координат в координаты экрана.

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

Ответ 2

Вот очень простой способ сделать контекстное меню, где вы щелкните его правой кнопкой мыши.

Обработать событие ColumnHeaderMouseClick

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

contextMenuHeader - это ContextMenuStrip, который может быть определен в представлении конструктора или во время выполнения.

Ответ 3

Чтобы получить координату курсора мыши, вы можете сделать это.

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

Ответ 4

Вы пытались использовать Перегрузку 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);
            }
        }
    }
}

Ответ 5

e.Location не отображает всплывающее меню в правильных координатах, вместо этого просто используйте свойство MousePosition следующим образом:

ContextMenuStrip.Show(MousePosition)

или, явно

ContextMenuStrip.Show(Control.MousePosition)

Ответ 6

Возвращенная позиция относится к ячейке. Поэтому мы должны добавить это смещение.

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

Ответ 7

Ты был почти прав. Вам просто нужно применить метод 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.