128

.NET winform アプリに datagridview があります。行を右クリックして、メニューをポップアップさせたいと思います。次に、コピー、検証などを選択したいと思います

A) メニューがポップアップするようにするにはどうすればよいですか? B) 右クリックされた行を見つけます。selectedIndex を使用できることはわかっていますが、選択内容を変更せずに右クリックできるはずですか? 現在、選択したインデックスを使用できますが、選択したものを変更せずにデータを取得する方法があれば便利です。

4

7 に答える 7

148

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

    }
}
于 2009-11-11T22:22:38.840 に答える
102

この質問は古いですが、答えは適切ではありません。コンテキスト メニューには、DataGridView に独自のイベントがあります。行コンテキスト メニューとセル コンテキスト メニューのイベントがあります。

これらの回答が適切でない理由は、さまざまな操作スキームを説明していないためです。アクセシビリティ オプション、リモート接続、または Metro/Mono/Web/WPF 移植が機能しない可能性があり、キーボード ショートカットが失敗します (Shift+F10 またはコンテキスト メニュー キー)。

マウスの右クリックでのセルの選択は、手動で処理する必要があります。コンテキスト メニューの表示は、UI によって処理されるため、処理する必要はありません。

これは、Microsoft Excel で使用されるアプローチを完全に模倣しています。セルが選択範囲の一部である場合、セルの選択は変更されず、どちらも変更されませんCurrentCell。そうでない場合は、古い範囲がクリアされ、セルが選択されて になりCurrentCellます。

これがよくわからない場合はCurrentCell、矢印キーを押したときにキーボードがフォーカスされる場所です。Selectedの一部かどうかですSelectedCells。コンテキスト メニューは、UI によって処理されるように、右クリックで表示されます。

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示します。

このコンテキストでは、 MultiSelectisTrueおよびSelectionModeisFullRowSelectです。これは単なる例であり、制限ではありません。

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    
        }
    }
}
于 2012-12-12T19:59:08.650 に答える
49

CellMouseDownでイベントを使用しDataGridViewます。イベント ハンドラーの引数から、クリックされたセルを特定できます。DataGridView でメソッドを使用するPointToClient()と、DataGridView へのポインターの相対位置を特定できるため、メニューを正しい位置にポップアップ表示できます。

(このパラメーターは、クリックしたセルに相対的なとDataGridViewCellMouseEventを与えるだけであり、コンテキスト メニューをポップアップするのに使用するのは簡単ではありません。)XY

これは、マウスの位置を取得し、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);
        }
    }
}
于 2011-04-02T22:02:09.307 に答える
48
  • 組み込みのエディターを使用して、フォームにコンテキストメニューを配置し、名前を付け、キャプションを設定します。
  • gridプロパティを使用してグリッドにリンクしますContextMenuStrip
  • グリッドの場合、処理するイベントを作成しますCellContextMenuStripNeeded
  • Event Args eにはe.ColumnIndex、便利なプロパティがありe.RowIndexます。

それe.RowIndexがあなたが求めていることだと思います。

提案:ユーザーがイベントを発生させた場合は、IDなどのデータをグリッドから取得するためCellContextMenuStripNeededに使用します。e.RowIndexIDをメニューイベントのタグアイテムとして保存します。

これで、ユーザーが実際にメニュー項目をクリックしたときに、Senderプロパティを使用してタグをフェッチします。IDを含むタグを使用して、必要なアクションを実行します。

于 2012-03-09T22:12:04.843 に答える
6

Simply drag a ContextMenu or ContextMenuStrip component into your form and visually design it, then assign it to the ContextMenu or ContextMenuStrip property of your desired control.

于 2009-11-11T22:31:06.390 に答える