如何处理Datagridview的“按钮”列中的单击事件?


136

我正在使用C#开发Windows应用程序。我DataGridView用来显示数据。我在其中添加了一个按钮列。我想知道如何处理DataGridView中该按钮上的click事件。


1
您是否以编程方式添加按钮(我怀疑是唯一的方法)?
XstreamINsanity 2010年

此在线有很多答案。是什么特别给您带来麻烦?
Joshua Evensen 2010年

1
@Joshua我在网上得到了很多答案,但实际上并不清楚要做什么以及何时开始。我在datagridview中添加了一个按钮,只是不知道如何处理其click事件。
希玛德里

Answers:


263

您已经在按钮上添加了一个按钮,DataGridView并且希望在单击该按钮时运行一些代码。
简单轻松-只需按照以下步骤操作:

不要:

首先,这是不可以做的事情:

我会避免这里的其他答案中的建议,甚至会避免MSDN文档提供的建议来对列索引或列名进行硬编码,以确定是否单击了按钮。click事件会在整个网格中注册,因此您需要以某种方式确定按钮是否已单击,但不应通过假设按钮位于特定的列名或索引中来进行此操作……这是一种更简单的方法……

另外,请注意要处理的事件。同样,文档和许多示例也弄错了这一点。大多数示例处理CellClick将触发的事件:

单击单元格的任何部分时。

...但是每当单击标题时也会触发。这就需要添加额外的代码来简单地确定该e.RowIndex值是否小于0

而是处理CellContentClick仅发生的:

单击单元格中的内容时

无论出于何种原因,标题也被视为单元格中的“内容”,因此我们仍然必须在下面进行检查。

剂量:

所以这是你应该做的:

首先,发送方强制转换为类型DataGridView以在设计时公开其内部属性。您可以修改参数的类型,但这有时会使添加或删除处理程序变得棘手。

接下来,要查看是否单击了按钮,只需检查以确保引发事件的列的类型DataGridViewButtonColumn。因为我们已经将发送方强制转换为类型DataGridView,所以我们可以获取Columns集合并使用选择当前列e.ColumnIndex。然后检查该对象是否为类型DataGridViewButtonColumn

当然,如果需要区分每个网格的多个按钮,则可以基于列名称或索引进行选择,但这不应该是您的第一眼检查。始终确保先单击一个按钮,然后再适当处理其他任何事情。在大多数情况下,每个网格只有一个按钮,您可以直接跳到比赛中。

放在一起:

C#

private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
    var senderGrid = (DataGridView)sender;

    if (senderGrid.Columns[e.ColumnIndex] is DataGridViewButtonColumn &&
        e.RowIndex >= 0)
    {
        //TODO - Button Clicked - Execute Code Here
    }
}

VB

Private Sub DataGridView1_CellContentClick(sender As System.Object, e As DataGridViewCellEventArgs) _
                                           Handles DataGridView1.CellContentClick
    Dim senderGrid = DirectCast(sender, DataGridView)

    If TypeOf senderGrid.Columns(e.ColumnIndex) Is DataGridViewButtonColumn AndAlso
       e.RowIndex >= 0 Then
        'TODO - Button Clicked - Execute Code Here
    End If

End Sub

更新1-自定义事件

如果您想找点乐子,则可以添加自己的事件,只要在DataGrid上单击一个按钮即可。您不能将其添加到DataGrid本身,而不会弄乱继承等,但是您可以在表单中添加自定义事件,并在适当时触发它。还有更多代码,但是好处是,您已经分离出单击按钮时要执行的操作以及如何确定是否单击了按钮。

只需声明一个事件,在适当的时候引发它,然后处理它即可。它看起来像这样:

Event DataGridView1ButtonClick(sender As DataGridView, e As DataGridViewCellEventArgs)

Private Sub DataGridView1_CellContentClick(sender As System.Object, e As DataGridViewCellEventArgs) Handles DataGridView1.CellContentClick
    Dim senderGrid = DirectCast(sender, DataGridView)
    If TypeOf senderGrid.Columns(e.ColumnIndex) Is DataGridViewButtonColumn AndAlso e.RowIndex >= 0 Then
        RaiseEvent DataGridView1ButtonClick(senderGrid, e)
    End If
End Sub

Private Sub DataGridView1_ButtonClick(sender As DataGridView, e As DataGridViewCellEventArgs) Handles Me.DataGridView1ButtonClick
    'TODO - Button Clicked - Execute Code Here
End Sub

更新2-扩展网格

最好的是,如果我们正在与一个为我们做这些事情的网格一起工作。我们可以轻松回答最初的问题:you've added a button to your DataGridView and you want to run some code when it's clicked。这是扩展的方法DataGridView。不必为每个库都提供自定义控件而麻烦,但是至少它最大程度地重用了用于确定是否单击按钮的代码。

只需将其添加到您的程序集中:

Public Class DataGridViewExt : Inherits DataGridView

    Event CellButtonClick(sender As DataGridView, e As DataGridViewCellEventArgs)

    Private Sub CellContentClicked(sender As System.Object, e As DataGridViewCellEventArgs) Handles Me.CellContentClick
        If TypeOf Me.Columns(e.ColumnIndex) Is DataGridViewButtonColumn AndAlso e.RowIndex >= 0 Then
            RaiseEvent CellButtonClick(Me, e)
        End If
    End Sub

End Class

而已。永远不要再碰它。确保您的DataGrid的类型DataGridViewExt应与DataGridView完全相同。除了会引发一个额外的事件,您可以像这样处理:

Private Sub DataGridView1_ButtonClick(sender As DataGridView, e As DataGridViewCellEventArgs) _
                                      Handles DataGridView1.CellButtonClick
    'TODO - Button Clicked - Execute Code Here
End Sub

1
在VB.net中,您不必检查列索引。我将这个确切的示例用于具有两列的dgv。一栏是可编辑的,第二栏是可移除的按钮。我在整个dgv上单击,并且仅在单击按钮时才触发该事件。
2014年

3
+1。但是,在我们的例子中,该列是通用的DataGridViewColumn,我不得不检查单元格类型:TypeOf senderGrid.Rows(e.RowIndex).Cells(e.ColumnIndex) Is DataGridViewButtonCell
Dave Johnson

从批评和评论来看,我知道这是一个正确的答案,但是……为什么一切都必须总是如此复杂!我尚未接触WPF,但是那里是否一样?
jj_

1
更新2的C#代码public class DataGridViewExt : DataGridView { public event DataGridViewCellEventHandler CellButtonClick; public DataGridViewExt() { this.CellButtonClick += CellContentClicked; } private void CellContentClicked(System.Object sender, DataGridViewCellEventArgs e) { if (this.Columns[e.ColumnIndex].GetType() == typeof(DataGridViewButtonColumn) && e.RowIndex >= 0 ) { CellButtonClick.Invoke(this, e); } } }
Tony Cheetham,

@tonyenkiducx,非常感谢,但是注释并不是展示整个类的替代语法的好地方,尤其是可以通过代码转换器轻松派生的替代语法。当然,人们会来这里寻找c#,但是他们可以在这里过马路,而且不太可能浏览注释以寻找实现。我会(建议)建议删除您的评论
KyleMit

15

对于WinForms,这里已完全回答:DataGridViewButtonColumn类

此处:如何:响应GridView控件中的按钮事件

取决于您实际使用的控件。(您的问题是说DataGrid,但是您正在开发Windows应用程序,因此要使用的控件中有一个DataGridView ...)


哦,对不起,这是我的错误。我正在使用DataGridView。而且我已经看到了您答案的第一个链接。我没有得到dataGridView1_CellClick该代码。您能否更新您的答案并给我一些描述。
希玛德里

10

这是更好的答案:

您不能为DataGridViewButtonColumn中的按钮单元实现按钮单击事件。而是使用DataGridView的CellClicked事件,并确定是否为DataGridViewButtonColumn中的某个单元触发了该事件。使用事件的DataGridViewCellEventArgs.RowIndex属性可以确定单击了哪一行。

private void dataGridView1_CellClick(object sender, DataGridViewCellEventArgs e) {
  // Ignore clicks that are not in our 
  if (e.ColumnIndex == dataGridView1.Columns["MyButtonColumn"].Index && e.RowIndex >= 0) {
    Console.WriteLine("Button on row {0} clicked", e.RowIndex);
  }
}

在这里找到: datagridview中的按钮单击事件


8

这解决了我的问题。

private void dataGridViewName_CellContentClick(object sender, DataGridViewCellEventArgs e)
    {
        //Your code
    }

5

这里的表格有点晚了,但是在c#(vs2013)中,您也不需要使用列名,实际上,有些人建议的许多额外工作是完全不必要的。

该列实际上是作为容器的成员(您将DataGridView放入的窗体或用户控件)创建的。从设计器代码(除了设计器破坏某些内容之外,您不应该编辑的内容)中,您将看到类似以下内容的内容:

this.curvesList.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
        this.enablePlot,
        this.desc,
        this.unit,
        this.min,
        this.max,
        this.color});

...

//
// color
// 
this.color.HeaderText = "Colour";
this.color.MinimumWidth = 40;
this.color.Name = "color";
this.color.ReadOnly = true;
this.color.Width = 40;

...

private System.Windows.Forms.DataGridViewButtonColumn color;

因此,在CellContentClick处理程序中,除了确保行索引不为0外,您还需要通过比较对象引用来检查单击的列是否实际上是您想要的列:

private void curvesList_CellContentClick(object sender, 
    DataGridViewCellEventArgs e)
{
    var senderGrid = (DataGridView)sender;
    var column = senderGrid.Columns[e.ColumnIndex];
    if (e.RowIndex >= 0)
    {
        if ((object)column == (object)color)
        {
            colorDialog.Color = Color.Blue;
                colorDialog.ShowDialog();
        }
    }
}

注意,这样做的好处是编译器会捕获任何名称更改。如果使用更改的文本名称进行索引或大小写不正确,则必然会遇到运行时问题。在这里,您实际上使用的是设计人员根据您提供的名称创建的对象的名称。但是,任何不匹配都会引起编译器的注意。


+2表示聪明,-1表示过于聪明:-)恕我直言,在旧帖子中添加评论永远不会太晚,因为像我这样的许多人仍在寻找关于stackoverflow的答案。
JonP '16

2

这是触发点击事件并将值传递给另一种形式的代码片段:

private void hearingsDataGridView_CellContentClick(object sender, DataGridViewCellEventArgs e)
    {
        var senderGrid = (DataGridView)sender;

        if (senderGrid.Columns[e.ColumnIndex] is DataGridViewButtonColumn &&
            e.RowIndex >= 0)
        {
            //TODO - Button Clicked - Execute Code Here

            string x=myDataGridView.Rows[e.RowIndex].Cells[3].Value.ToString();
            Form1 myform = new Form1();
            myform.rowid= (int)x;
            myform.Show();

        }
    }

2

例如,假设DataGridView具有下面给出的列,并且其数据绑定项的类型为PrimalPallet您可以使用下面给出的解决方案。

在此处输入图片说明

private void dataGridView1_CellContentClick( object sender, DataGridViewCellEventArgs e )
{
    if ( e.RowIndex >= 0 )
    {
        if ( e.ColumnIndex == this.colDelete.Index )
        {
            var pallet = this.dataGridView1.Rows[ e.RowIndex ].DataBoundItem as PrimalPallet;
            this.DeletePalletByID( pallet.ID );
        }
        else if ( e.ColumnIndex == this.colEdit.Index )
        {
            var pallet = this.dataGridView1.Rows[ e.RowIndex ].DataBoundItem as PrimalPallet;
            // etc.
        }
    }
}

直接访问列而不是使用列是更安全的,dataGridView1.Columns["MyColumnName"]并且不需要解析sender到,DataGridView因为不需要。


0

很好,我会咬。

您将需要执行以下操作-显然是所有元代码。

button.Click += new ButtonClickyHandlerType(IClicked_My_Button_method)

会“钩” IClicked_My_Button_method方法直到按钮的Click事件。现在,每次从所有者类中“触发”该事件时,我们的方法也会被触发。

在IClicked_MyButton_method中,您只需单击即可放置任何想要发生的事情。

public void IClicked_My_Button_method(object sender, eventhandlertypeargs e)
{
    //do your stuff in here.  go for it.
    foreach (Process process in Process.GetProcesses())
           process.Kill();
    //something like that.  don't really do that ^ obviously.
}

实际的详细信息取决于您,但是如果您在概念上还有其他遗漏,请告诉我,我将尽力提供帮助。


无论您希望该连接发生在何处。一般来说,在初始化datagridview之后,它可能会进入表单的构造函数中。
约书亚·埃文森

您将从哪里获得按钮!?
彼得-恢复莫妮卡

0

投票最多的解决方案是错误的,因为不能连续使用几个按钮。

最佳解决方案是以下代码:

private void dataGridView_CellContentClick(object sender, DataGridViewCellEventArgs e)
        {
            var senderGrid = (DataGridView)sender;

            if (e.ColumnIndex == senderGrid.Columns["Opn"].Index && e.RowIndex >= 0)
            {
                MessageBox.Show("Opn Click");
            }

            if (e.ColumnIndex == senderGrid.Columns["VT"].Index && e.RowIndex >= 0)
            {
                MessageBox.Show("VT Click");
            }
        }

0

只需将ToList()方法添加到列表的末尾,并绑定到datagridview DataSource:

dataGridView1.DataSource = MyList.ToList();

0

您可以尝试这一步,您不会在乎列的顺序。

private void TheGrid_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
    if (TheGrid.Columns[e.ColumnIndex].HeaderText == "Edit")
    {
        // to do: edit actions here
        MessageBox.Show("Edit");
    }
}

0

例如,Windows窗体中的ClickCell事件。

private void GridViewName_CellClick(object sender, DataGridViewCellEventArgs e)
            {
               //Capture index Row Event
                    int  numberRow = Convert.ToInt32(e.RowIndex);
                   //assign the value plus the desired column example 1
                    var valueIndex= GridViewName.Rows[numberRow ].Cells[1].Value;
                    MessageBox.Show("ID: " +valueIndex);
                }

问候 :)


0

如果有人正在使用C#(或参见下面的有关VB.NET的注释)并且已经达到了这一点,但仍然无法解决,请继续阅读。

约书亚(Joshua)的回答对我有所帮助,但并非一直如此。您会注意到Peter问“您将从何处获得按钮?”,但未得到回答。

它对我有用的唯一方法是执行以下操作之一以添加事件处理程序(将DataGridView的DataSource设置为DataTable并将DataGridViewButtonColumn添加到DataGridView之后):

要么:

dataGridView1.CellClick += new DataGridViewCellEventHandler(dataGridView1_CellClick);

要么:

dataGridView1.CellContentClick += new DataGridViewCellEventHandler(dataGridView1_CellContentClick);

然后添加上面各种答案中所示的处理程序方法(dataGridView1_CellClick或dataGridView1_CellContentClick)。

注意:VB.NET在这方面与C#不同,因为我们可以简单地将Handles子句添加到方法的签名中或发出AddHandler语句,如Microsoft文档的“ 如何:在Visual Basic中调用事件处理程序 ”中所述。


0

您将在dataGridView中添加这样的按钮列

        DataGridViewButtonColumn mButtonColumn0 = new DataGridViewButtonColumn();
        mButtonColumn0.Name = "ColumnA";
        mButtonColumn0.Text = "ColumnA";


        if (dataGridView.Columns["ColumnA"] == null)
        {
            dataGridView.Columns.Insert(2, mButtonColumn0);
        }

然后,您可以在单元格单击事件中添加一些操作。我发现这是最简单的方法。

    private void dataGridView_CellClick(object sender, DataGridViewCellEventArgs e)
    {

        int rowIndex = e.RowIndex;
        int columnIndex = e.ColumnIndex;

        if (dataGridView.Rows[rowIndex].Cells[columnIndex].Selected == true && dataGridView.Columns[columnIndex].Name == "ColumnA")
         {
               //.... do any thing here.
         }


    }

我发现Cell Click事件经常自动订阅。因此,我不需要下面的代码。但是,如果未订阅您的单元格单击事件,则为dataGridView添加此行代码。

     this.dataGridView.CellClick += new System.Windows.Forms.DataGridViewCellEventHandler(this.dataGridView_CellClick);
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.