Si bien esta pregunta es antigua, las respuestas no son las correctas. Los menús contextuales tienen sus propios eventos en DataGridView.Hay un evento para el menú contextual de la fila y el menú contextual de la celda.
La razón por la cual estas respuestas no son las adecuadas es que no tienen en cuenta los diferentes esquemas de operación. Es posible que las opciones de accesibilidad, las conexiones remotas o las conexiones Metro/Mono/Web/WPF no funcionen y los atajos de teclado fallarán a la derecha (Shift + F10 o la tecla de menú contextual).
La selección de celda con el clic derecho del mouse tiene que ser manejada manualmente. No es necesario que se muestre el menú contextual, ya que la IU lo maneja.
Esto imita por completo el enfoque utilizado por Microsoft Excel. Si una celda es parte de un rango seleccionado, la selección de celda no cambia y tampoco lo hace CurrentCell
. Si no es así, se borra el rango anterior y se selecciona la celda y se convierte en CurrentCell
.
Si no está seguro de esto, CurrentCell
es donde el teclado tiene foco cuando presiona las teclas de flecha. Selected
es si es parte de SelectedCells
. El menú contextual se mostrará con un clic derecho manejado por la IU.
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;
}
}
}
atajos de teclado no mostrar el menú de contexto por defecto, así que habrá que añadirlos en.
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);
}
}
}
}
he vuelto a trabajar este código para trabajar de forma estática, por lo que se pueden copiar y pegar en cualquier evento.
La clave es usar CellContextMenuStripNeeded
ya que esto le dará el menú contextual.
Aquí hay un ejemplo usando CellContextMenuStripNeeded
donde puede especificar qué menú contextual mostrar si desea tener diferentes por fila.
En este contexto MultiSelect
es True
y SelectionMode
es FullRowSelect
. Esto es solo por el ejemplo y no una limitación.
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
}
}
}
correcta! y una nota para usted, var r = dataGridView1.HitTest (e.X, e.Y); r.RowIndex funciona MUCHO MEJOR que usar mouse o currentMouseOverRow –
usando .ToString() en string.Format es innecesariamente. – msavara
Este método es antiguo: una vista de tabla de datos tiene una propiedad: ContextMenu. El menú contextual se abrirá tan pronto como el operador haga clic derecho. El evento correspondiente ContextMenuOpening le brinda la oportunidad de decidir qué mostrar según la celda actual o las celdas seleccionadas. Consulte una de las otras respuestas –