右键单击选择Datagridview中的行并显示菜单以删除它

68

我在DataGridView中有几个列,每行都有数据。我在这里看到了一些解决方案,但我无法将它们结合起来!

我想实现的功能是右键单击一行时,选择整行并显示一个菜单,其中有删除行的选项,选择该选项后将删除该行。

我尝试过几次,但都没有成功,而且看起来很混乱。我应该怎么办?


你的问题太模糊了。请在遇到问题的地方添加更多细节。你想要做什么并不是很困难。 - leppie
12个回答

118

最终问题得以解决:

  • 在Visual Studio中创建一个名为"DeleteRow"的ContextMenuStrip项

  • 然后将其与DataGridView连接

使用以下代码帮助我使其工作。

this.MyDataGridView.MouseDown += new System.Windows.Forms.MouseEventHandler(this.MyDataGridView_MouseDown);
this.DeleteRow.Click += new System.EventHandler(this.DeleteRow_Click);

这里是很酷的部分

private void MyDataGridView_MouseDown(object sender, MouseEventArgs e)
{
    if(e.Button == MouseButtons.Right)
    {
        var hti = MyDataGridView.HitTest(e.X, e.Y);
        MyDataGridView.ClearSelection();
        MyDataGridView.Rows[hti.RowIndex].Selected = true;
    }
}

private void DeleteRow_Click(object sender, EventArgs e)
{
    Int32 rowToDelete = MyDataGridView.Rows.GetFirstRow(DataGridViewElementStates.Selected);
    MyDataGridView.Rows.RemoveAt(rowToDelete);
    MyDataGridView.ClearSelection();
}

你在 DeleteRow_Click 中使用了哪个控件? - Crimsonland
当网格上存在“ContextMenuStripNeeded”事件时,此解答似乎无效。使用“CellMouseDown”可以解决问题。 - JB.
4
非常有帮助,谢谢!如果你正在使用“AllowUserToAddRows”,在执行“RemoveAt()”之前,你可能需要检查“MyDataGridView.Rows[rowToDelete].IsNewRow”是否为真,以防用户右键单击了新行。 - Henrik Heimbuerger
谢谢分享!我建议也检查一下点击类型:if (hit.Type == DataGridViewHitTestType.Cell) { ... }参见:https://msdn.microsoft.com/zh-cn/library/system.windows.forms.datagridview.hittest(v=vs.110).aspx - Ben Keene
1
谢谢。在设置 hti 后,我会添加一个“if (hti.RowIndex!= -1)”检查来处理用户单击空白区域的情况。 - Sohail

45

为了完整性起见,最好使用网格事件而不是鼠标事件。

首先设置您的数据网格属性:

SelectionMode设置为FullRowSelect和RowTemplate / ContextMenuStrip设置为上下文菜单。

创建CellMouseDown事件:

private void myDatagridView_CellMouseDown(object sender, DataGridViewCellMouseEventArgs e)
{
    if (e.Button == MouseButtons.Right)
    {
        int rowSelected = e.RowIndex;
        if (e.RowIndex != -1)
        {
            this.myDatagridView.ClearSelection();
            this.myDatagridView.Rows[rowSelected].Selected = true;
        }
        // you now have the selected row with the context menu showing for the user to delete etc.
    }
}

еҪ“еӯҳеңЁ ContextMenuStripNeeded ж—¶пјҢжӯӨзӯ”жЎҲжңүж•ҲгҖӮеҹәдәҺ MouseDown зҡ„и§ЈеҶіж–№жЎҲеҲҷж— ж•ҲгҖӮ - JB.
@peter 如果选择了多行,如何获取这些行的索引? - Vbp
嗨vbp,如果问题还没有得到解答,我认为您需要提出一个新问题,本问题涉及仅选择1行。 - 27k1

11
private void dgvOferty_CellContextMenuStripNeeded(object sender, DataGridViewCellContextMenuStripNeededEventArgs e)
    {
        dgvOferty.ClearSelection();
        int rowSelected = e.RowIndex;
        if (e.RowIndex != -1)
        {
            this.dgvOferty.Rows[rowSelected].Selected = true;
        }
        e.ContextMenuStrip = cmstrip;
    }

TADA :D. 最简单的方法。如果需要定制单元格,只需稍作修改即可。


2
最佳方法,也适用于仅使用键盘的情况。但是请注意:仅在附加了数据源时才有效。MSDN关于DataGridView.CellContextMenuStripNeeded事件的说明:“仅当设置了DataGridView控件的DataSource属性或其VirtualMode属性为true时,才会发生CellContextMenuStripNeeded事件。” - Harald Coppoolse
cmstrip 变量引用的是什么? - reformed
@reformed 引用的是从工具箱添加的 ContextMenuStrip。 - Mirwise Khan

3

仅为鼠标按下事件添加事件会更加容易:

private void MyDataGridView_MouseDown(object sender, MouseEventArgs e)
{
    if (e.Button == MouseButtons.Right)
    {
        var hti = MyDataGridView.HitTest(e.X, e.Y);
        MyDataGridView.Rows[hti.RowIndex].Selected = true;
        MyDataGridView.Rows.RemoveAt(rowToDelete);
        MyDataGridView.ClearSelection();
    }
}

这很简单。当然,你需要像之前提到的那样初始化mousedown事件:
this.MyDataGridView.MouseDown += new System.Windows.Forms.MouseEventHandler(this.MyDataGridView_MouseDown);

在你的构造函数中。


2

根据@Data-Base的答案,只有在选择模式为FullRow时才能生效。

  MyDataGridView.SelectionMode = DataGridViewSelectionMode.FullRowSelect;

但是如果您需要在CellSelect模式下使其正常工作

 MyDataGridView.SelectionMode = DataGridViewSelectionMode.CellSelect;

 // for cell selection
 private void MyDataGridView_MouseDown(object sender, MouseEventArgs e)
 {
  if(e.Button == MouseButtons.Right)
    {
       var hit = MyDataGridView.HitTest(e.X, e.Y);
       MyDataGridView.ClearSelection();

       // cell selection
       MyDataGridView[hit.ColumnIndex,hit.RowIndex].Selected = true;
   }
}

private void DeleteRow_Click(object sender, EventArgs e)
{
   int rowToDelete = MyDataGridView.Rows.GetFirstRow(DataGridViewElementStates.Selected);
   MyDataGridView.Rows.RemoveAt(rowToDelete);
   MyDataGridView.ClearSelection();
}

2

所有对这个问题的回答都是基于鼠标单击事件的。你也可以为你的DataGridview指定一个ContenxtMenuStrip,并在用户在DataGridView上点击鼠标右键时检查是否有选中的行,并决定是否要显示ContenxtMenuStrip。你可以通过在ContextMenuStripOpening事件中设置CancelEventArgs.Cancel的值来实现。请保留HTML标签。

    private void MyContextMenuStrip_Opening(object sender, CancelEventArgs e)
    {
        //Only show ContextMenuStrip when there is 1 row selected.
        if (MyDataGridView.SelectedRows.Count != 1) e.Cancel = true;
    }

但是,如果您有几个上下文菜单条,每个菜单条都包含不同的选项,取决于选择的内容,我也会选择鼠标点击的方法。


1
private void MyDataGridView_MouseDown(object sender, MouseEventArgs e)
{
    if(e.Button == MouseButtons.Right)
    {
        MyDataGridView.ClearSelection();
        MyDataGridView.Rows[e.RowIndex].Selected = true;
    }
}

private void DeleteRow_Click(object sender, EventArgs e)
{
    Int32 rowToDelete = MyrDataGridView.Rows.GetFirstRow(DataGridViewElementStates.Selected);
    MyDataGridView.Rows.RemoveAt(rowToDelete);
    MyDataGridView.ClearSelection();
}

1
这对我来说是没有任何错误的工作:
this.dataGridView2.MouseDown += new System.Windows.Forms.MouseEventHandler(this.MyDataGridView_MouseDown); 
this.dataGridView2.Click += new System.EventHandler(this.DeleteRow_Click);

并且这个

private void MyDataGridView_MouseDown(object sender, MouseEventArgs e)
{
    if (e.Button == MouseButtons.Right)
    {
        var hti = dataGridView2.HitTest(e.X, e.Y);
        dataGridView2.ClearSelection();
        dataGridView2.Rows[hti.RowIndex].Selected = true;
    }

}


private void DeleteRow_Click(object sender, EventArgs e)
{
    Int32 rowToDelete = dataGridView2.Rows.GetFirstRow(DataGridViewElementStates.Selected);
    if (rowToDelete == -1) { }
    else 
    {
        dataGridView2.Rows.RemoveAt(rowToDelete);
        dataGridView2.ClearSelection();
    }
}

1
private void dataGridView1_CellContextMenuStripNeeded(object sender, 
DataGridViewCellContextMenuStripNeededEventArgs e)
{            
    if (e.RowIndex != -1)
    {
        dataGridView1.ClearSelection();
        this.dataGridView1.Rows[e.RowIndex].Selected = true;
        e.ContextMenuStrip = contextMenuStrip1;
    }
}

0

你也可以在事件代码中使用以下内容来使其更简单:

private void MyDataGridView_MouseDown(object sender, MouseEventArgs e) 
{     
    if (e.Button == MouseButtons.Right)     
    {         
        rowToDelete = e.RowIndex;
        MyDataGridView.Rows.RemoveAt(rowToDelete);         
        MyDataGridView.ClearSelection();     
    } 
}

这只会在没有警告或确认的情况下删除该行。我确信OP不想要这个。 - ProfK

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接