щелкните правой кнопкой мыши контекстное меню для просмотра данных - PullRequest
100 голосов
/ 12 ноября 2009

У меня есть сетевое представление в WinNET-приложении .NET. Я хотел бы щелкнуть правой кнопкой мыши по строке и получить всплывающее меню. Затем я хотел бы выбрать такие вещи, как копирование, проверка и т. Д.

Как мне сделать A) всплывающее меню B) найти строку, по которой щелкнули правой кнопкой мыши. Я знаю, что могу использовать selectedIndex, но я должен иметь возможность щелкнуть правой кнопкой мыши, не меняя то, что выбрано? Прямо сейчас я мог бы использовать выбранный индекс, но если есть способ получить данные без изменения выбранного, это было бы полезно.

Ответы [ 7 ]

131 голосов
/ 12 ноября 2009

Вы можете использовать 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));

    }
}
75 голосов
/ 12 декабря 2012

Пока этот вопрос старый, ответы не правильные. Контекстные меню имеют свои собственные события в 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    
        }
    }
}
43 голосов
/ 03 апреля 2011

Используйте событие CellMouseDown для DataGridView. Из аргументов обработчика событий вы можете определить, какая ячейка была нажата. Используя метод PointToClient() в DataGridView, вы можете определить относительное положение указателя на DataGridView, чтобы вы могли всплывающее меню в правильном месте.

(Параметр 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);
        }
    }
}
37 голосов
/ 10 марта 2012
  • Добавьте в форму контекстное меню, назовите его, установите подписи и т. Д. С помощью встроенного редактора
  • Свяжите это со своей сеткой, используя свойство сетки ContextMenuStrip
  • Для вашей сетки создайте событие для обработки CellContextMenuStripNeeded
  • Аргументы событий e имеют полезные свойства e.ColumnIndex, e.RowIndex.

Я считаю, что e.RowIndex - это то, что вы просите.

Предложение: когда пользователь вызывает ваше событие CellContextMenuStripNeeded, используйте e.RowIndex для получения данных из вашей сетки, таких как идентификатор. Сохраните идентификатор как элемент тега события меню.

Теперь, когда пользователь действительно щелкает по вашему пункту меню, используйте свойство Sender для получения тега. Используйте тег, содержащий ваш идентификатор, чтобы выполнить необходимое действие.

4 голосов
/ 20 декабря 2017

Выполните следующие действия:

  1. Создайте контекстное меню, например: Sample context menu

  2. Пользователь должен щелкнуть правой кнопкой мыши по строке, чтобы получить это меню. Нам нужно обработать событие _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)
        {

        }
    }
}

и вывод будет:

Final output

4 голосов
/ 12 ноября 2009

Просто перетащите компонент ContextMenu или ContextMenuStrip в форму и визуально создайте его, затем назначьте его свойству ContextMenu или ContextMenuStrip нужного элемента управления.

3 голосов
/ 22 июня 2014

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