Щелкните правой кнопкой мыши контекстное меню для datagridview
У меня есть представление данных в приложении WinNET.NET. Я хотел бы щелкнуть правой кнопкой мыши по строке и получить всплывающее меню. Затем я хотел бы выбрать такие вещи, как копирование, проверка и т. Д.
Как мне сделать A) всплывающее меню B) найти строку, по которой щелкнули правой кнопкой мыши. Я знаю, что могу использовать selectedIndex, но я должен иметь возможность щелкнуть правой кнопкой мыши, не меняя то, что выбрано? Прямо сейчас я мог бы использовать выбранный индекс, но если есть способ получить данные, не меняя то, что выбрано, это было бы полезно.
8 ответов
Вы можете использовать CellMouseEnter и CellMouseLeave для отслеживания номера строки, над которой в данный момент наведена мышь.
Затем используйте объект ContextMenu для отображения всплывающего меню, настроенного для текущей строки.
Вот быстрый и грязный пример того, что я имею в виду...
private void dataGridView1_MouseClick(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Right)
{
ContextMenu m = new ContextMenu();
m.MenuItems.Add(new MenuItem("Cut"));
m.MenuItems.Add(new MenuItem("Copy"));
m.MenuItems.Add(new MenuItem("Paste"));
int currentMouseOverRow = dataGridView1.HitTest(e.X,e.Y).RowIndex;
if (currentMouseOverRow >= 0)
{
m.MenuItems.Add(new MenuItem(string.Format("Do something to row {0}", currentMouseOverRow.ToString())));
}
m.Show(dataGridView1, new Point(e.X, e.Y));
}
}
Пока этот вопрос старый, ответы не правильные. Контекстные меню имеют свои собственные события в DataGridView. Существует событие для контекстного меню строки и контекстного меню ячейки.
Причина, по которой эти ответы не являются правильными, заключается в том, что они не учитывают различные схемы работы. Опции специальных возможностей, удаленные подключения или перенос Metro/Mono/Web/WPF могут не работать, и сочетания клавиш не будут работать сразу же (Shift+F10 или клавиша контекстного меню).
Выбор ячейки при щелчке правой кнопкой мыши должен выполняться вручную. Показывать контекстное меню не нужно, поскольку это обрабатывается пользовательским интерфейсом.
Это полностью имитирует подход, используемый Microsoft Excel. Если ячейка является частью выбранного диапазона, выбор ячейки не изменяется и не изменяется CurrentCell
, Если это не так, старый диапазон очищается, и ячейка выбирается и становится CurrentCell
,
Если вам неясно, CurrentCell
где клавиатура имеет фокус при нажатии клавиш со стрелками. Selected
является ли это частью SelectedCells
, Контекстное меню будет отображаться при щелчке правой кнопкой мыши в соответствии с пользовательским интерфейсом.
private void dgvAccount_CellMouseDown(object sender, DataGridViewCellMouseEventArgs e)
{
if (e.ColumnIndex != -1 && e.RowIndex != -1 && e.Button == System.Windows.Forms.MouseButtons.Right)
{
DataGridViewCell c = (sender as DataGridView)[e.ColumnIndex, e.RowIndex];
if (!c.Selected)
{
c.DataGridView.ClearSelection();
c.DataGridView.CurrentCell = c;
c.Selected = true;
}
}
}
Сочетания клавиш не отображают контекстное меню по умолчанию, поэтому мы должны добавить их в.
private void dgvAccount_KeyDown(object sender, KeyEventArgs e)
{
if ((e.KeyCode == Keys.F10 && e.Shift) || e.KeyCode == Keys.Apps)
{
e.SuppressKeyPress = true;
DataGridViewCell currentCell = (sender as DataGridView).CurrentCell;
if (currentCell != null)
{
ContextMenuStrip cms = currentCell.ContextMenuStrip;
if (cms != null)
{
Rectangle r = currentCell.DataGridView.GetCellDisplayRectangle(currentCell.ColumnIndex, currentCell.RowIndex, false);
Point p = new Point(r.X + r.Width, r.Y + r.Height);
cms.Show(currentCell.DataGridView, p);
}
}
}
}
Я переработал этот код, чтобы он работал статически, чтобы вы могли копировать и вставлять их в любое событие.
Ключ должен использовать CellContextMenuStripNeeded
так как это даст вам контекстное меню.
Вот пример использования CellContextMenuStripNeeded
где вы можете указать, какое контекстное меню показывать, если хотите, чтобы в строке было несколько разных меню.
В данном контексте MultiSelect
является True
а также SelectionMode
является FullRowSelect
, Это только для примера, а не ограничения.
private void dgvAccount_CellContextMenuStripNeeded(object sender, DataGridViewCellContextMenuStripNeededEventArgs e)
{
DataGridView dgv = (DataGridView)sender;
if (e.RowIndex == -1 || e.ColumnIndex == -1)
return;
bool isPayment = true;
bool isCharge = true;
foreach (DataGridViewRow row in dgv.SelectedRows)
{
if ((string)row.Cells["P/C"].Value == "C")
isPayment = false;
else if ((string)row.Cells["P/C"].Value == "P")
isCharge = false;
}
if (isPayment)
e.ContextMenuStrip = cmsAccountPayment;
else if (isCharge)
e.ContextMenuStrip = cmsAccountCharge;
}
private void cmsAccountPayment_Opening(object sender, CancelEventArgs e)
{
int itemCount = dgvAccount.SelectedRows.Count;
string voidPaymentText = "&Void Payment"; // to be localized
if (itemCount > 1)
voidPaymentText = "&Void Payments"; // to be localized
if (tsmiVoidPayment.Text != voidPaymentText) // avoid possible flicker
tsmiVoidPayment.Text = voidPaymentText;
}
private void cmsAccountCharge_Opening(object sender, CancelEventArgs e)
{
int itemCount = dgvAccount.SelectedRows.Count;
string deleteChargeText = "&Delete Charge"; //to be localized
if (itemCount > 1)
deleteChargeText = "&Delete Charge"; //to be localized
if (tsmiDeleteCharge.Text != deleteChargeText) // avoid possible flicker
tsmiDeleteCharge.Text = deleteChargeText;
}
private void tsmiVoidPayment_Click(object sender, EventArgs e)
{
int paymentCount = dgvAccount.SelectedRows.Count;
if (paymentCount == 0)
return;
bool voidPayments = false;
string confirmText = "Are you sure you would like to void this payment?"; // to be localized
if (paymentCount > 1)
confirmText = "Are you sure you would like to void these payments?"; // to be localized
voidPayments = (MessageBox.Show(
confirmText,
"Confirm", // to be localized
MessageBoxButtons.YesNo,
MessageBoxIcon.Warning,
MessageBoxDefaultButton.Button2
) == DialogResult.Yes);
if (voidPayments)
{
// SQLTransaction Start
foreach (DataGridViewRow row in dgvAccount.SelectedRows)
{
//do Work
}
}
}
private void tsmiDeleteCharge_Click(object sender, EventArgs e)
{
int chargeCount = dgvAccount.SelectedRows.Count;
if (chargeCount == 0)
return;
bool deleteCharges = false;
string confirmText = "Are you sure you would like to delete this charge?"; // to be localized
if (chargeCount > 1)
confirmText = "Are you sure you would like to delete these charges?"; // to be localized
deleteCharges = (MessageBox.Show(
confirmText,
"Confirm", // to be localized
MessageBoxButtons.YesNo,
MessageBoxIcon.Warning,
MessageBoxDefaultButton.Button2
) == DialogResult.Yes);
if (deleteCharges)
{
// SQLTransaction Start
foreach (DataGridViewRow row in dgvAccount.SelectedRows)
{
//do Work
}
}
}
- Добавьте в форму контекстное меню, назовите его, установите подписи и т. Д. С помощью встроенного редактора.
- Свяжите это со своей сеткой, используя свойство сетки
ContextMenuStrip
- Для вашей сетки создайте событие для обработки
CellContextMenuStripNeeded
- Аргументы событий имеют полезные свойства
e.ColumnIndex
,e.RowIndex
,
я полагаю, что e.RowIndex
это то, что вы просите.
Предложение: когда пользователь вызывает ваше событие CellContextMenuStripNeeded
стрелять, использовать e.RowIndex
чтобы получить данные из вашей сетки, такие как идентификатор. Сохраните идентификатор в качестве элемента тега события меню.
Теперь, когда пользователь фактически щелкает по вашему пункту меню, используйте свойство Sender для извлечения тега. Используйте тег, содержащий ваш идентификатор, чтобы выполнить необходимое действие.
Использовать CellMouseDown
событие на DataGridView
, Из аргументов обработчика событий вы можете определить, какая ячейка была нажата. С использованием PointToClient()
Метод DataGridView позволяет определить относительную позицию указателя на DataGridView, поэтому вы можете открыть меню в правильном месте.
(The DataGridViewCellMouseEvent
параметр просто дает вам X
а также Y
относительно ячейки, которую вы щелкнули, что не так просто использовать для всплывающего контекстного меню.)
Это код, который я использовал, чтобы получить позицию мыши, а затем настроить положение DataGridView:
var relativeMousePosition = DataGridView1.PointToClient(Cursor.Position);
this.ContextMenuStrip1.Show(DataGridView1, relativeMousePosition);
Весь обработчик событий выглядит так:
private void DataGridView1_CellMouseDown(object sender, DataGridViewCellMouseEventArgs e)
{
// Ignore if a column or row header is clicked
if (e.RowIndex != -1 && e.ColumnIndex != -1)
{
if (e.Button == MouseButtons.Right)
{
DataGridViewCell clickedCell = (sender as DataGridView).Rows[e.RowIndex].Cells[e.ColumnIndex];
// Here you can do whatever you want with the cell
this.DataGridView1.CurrentCell = clickedCell; // Select the clicked cell, for instance
// Get mouse position relative to the vehicles grid
var relativeMousePosition = DataGridView1.PointToClient(Cursor.Position);
// Show the context menu
this.ContextMenuStrip1.Show(DataGridView1, relativeMousePosition);
}
}
}
Следуйте шагам:
Пользователь должен щелкнуть правой кнопкой мыши по строке, чтобы получить это меню. Нам нужно обработать событие _MouseClick и событие _CellMouseDown.
selectedBiodataid - это переменная, которая содержит информацию о выбранной строке.
Вот код:
private void dgrdResults_MouseClick(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Right)
{
contextMenuStrip1.Show(Cursor.Position.X, Cursor.Position.Y);
}
}
private void dgrdResults_CellMouseDown(object sender, DataGridViewCellMouseEventArgs e)
{
//handle the row selection on right click
if (e.Button == MouseButtons.Right)
{
try
{
dgrdResults.CurrentCell = dgrdResults.Rows[e.RowIndex].Cells[e.ColumnIndex];
// Can leave these here - doesn't hurt
dgrdResults.Rows[e.RowIndex].Selected = true;
dgrdResults.Focus();
selectedBiodataId = Convert.ToInt32(dgrdResults.Rows[e.RowIndex].Cells[1].Value);
}
catch (Exception)
{
}
}
}
и результат будет:
Просто перетащите компонент ContextMenu или ContextMenuStrip в форму и визуально спроектируйте его, затем назначьте его свойству ContextMenu или ContextMenuStrip желаемого элемента управления.
Для позиции для контекстного меню вы обнаружили проблему, которая мне нужна, чтобы она была относительно DataGridView, и событие, которое мне нужно было использовать, дает отношение относительно нажатой ячейки. Я не нашел лучшего решения, поэтому я реализовал эту функцию в классе commons, поэтому я вызываю его из любого места, где мне нужно.
Это довольно проверено и работает хорошо. Надеюсь, вы найдете это полезным.
/// <summary>
/// When DataGridView_CellMouseClick ocurs, it gives the position relative to the cell clicked, but for context menus you need the position relative to the DataGridView
/// </summary>
/// <param name="dgv">DataGridView that produces the event</param>
/// <param name="e">Event arguments produced</param>
/// <returns>The Location of the click, relative to the DataGridView</returns>
public static Point PositionRelativeToDataGridViewFromDataGridViewCellMouseEventArgs(DataGridView dgv, DataGridViewCellMouseEventArgs e)
{
int x = e.X;
int y = e.Y;
if (dgv.RowHeadersVisible)
x += dgv.RowHeadersWidth;
if (dgv.ColumnHeadersVisible)
y += dgv.ColumnHeadersHeight;
for (int j = 0; j < e.ColumnIndex; j++)
if (dgv.Columns[j].Visible)
x += dgv.Columns[j].Width;
for (int i = 0; i < e.RowIndex; i++)
if (dgv.Rows[i].Visible)
y += dgv.Rows[i].Height;
return new Point(x, y);
}
На эту тему есть простой ответ, который заключается в использованииCellMouseDown
- После проектирования вашего
ContextMenu
// somewhere in your code
ContextMenu cm = new ContextMenu();
cm.MenuItems.Add(new MenuItem("Option1"));
cm.MenuItems.Add(new MenuItem("Option2"));
- Назначить его
DataGridView
myDataView.ContextMenu = cm;
- Получить данные из ячейки CLICKED без изменения
Selected
один
private void myDataView_CellMouseDown(object sender, DataGridViewCellMouseEventArgs e)
{
if (e.Button == MouseButtons.Right)
{
string myData = myDataView.Rows[e.RowIndex].Cells[e.ColumnIndex].Value.ToString();
// Now ADD the captured DATA to the ContextMenu
cm.MenuItems.Add(new MenuItem("myData"));
// OR if you are doing it by the designer and YOU ALREADY have an Item
// you can simply change the name of it in the designer page to your
// desired one and then just change the Text of it
MenuItem_BTN.Text = "$Properties of {myData}";
}
}