Как правильно позиционировать контекстное меню, когда я нажимаю правой кнопкой мыши заголовок столбца 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));
}
}
}
Ответы
Ответ 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
.