【问题标题】:How to handle click event in Button Column in Datagridview?如何处理Datagridview中按钮列的点击事件?
【发布时间】:2010-08-26 16:34:48
【问题描述】:

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

【问题讨论】:

  • 您是否以编程方式添加按钮(我怀疑这是唯一的方法)?
  • 网上有很多可用的答案。特别是什么给你带来了麻烦?
  • @Joshua 我在网上得到了很多答案,但并不真正知道该做什么以及何时开始。我在 datagridview 中添加了一个按钮,只是不知道如何处理它的点击事件。

标签: c# .net winforms datagridview


【解决方案1】:

您已向DataGridView 添加了一个按钮,并且您希望在单击该按钮时运行一些代码。

简单易行 - 只需按照以下步骤操作:

注意事项

首先,这是要做的事情:

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

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

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

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

改为处理仅发生的CellContentClick

单击单元格内的内容时

无论出于何种原因,column 标头也被视为单元格中的“内容”,因此我们仍然需要在下面检查。

做事

所以你应该这样做:

首先,强制发送者键入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

【讨论】:

  • 在 VB.net 中,您不必检查列索引。我将这个确切的示例用于具有两列的 dgv。一列可编辑,第二列带有删除按钮。我在整个 dgv 上单击,事件仅在我单击按钮时触发。
  • +1。但是,在我们的例子中,该列是一个通用的 DataGridViewColumn,我必须检查单元格类型:TypeOf senderGrid.Rows(e.RowIndex).Cells(e.ColumnIndex) Is DataGridViewButtonCell
  • 从upvotes 和 cmets 来看,我知道这是一个正确的答案,但是......为什么一切都必须如此复杂!我还没有接触过WPF,但是那里会一样吗?
  • 更新 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); } } }
  • @tonyenkiducx,感谢,但 cmets 并不是展示整个类的替代语法的好地方,尤其是可以通过 code converter 轻松派生的语法。当然,人们会来这里寻找 c#,但他们自己可以在那里人行横道,而且不太可能浏览 cmets 以寻找实现。我会(恭敬地)建议删除您的评论
【解决方案2】:

WinForms 在这里得到了完整的回答:DataGridViewButtonColumn Class

这里:How to: Respond to Button Events in a GridView Control

对于 Asp.Net,取决于您实际使用的控件。 (您的问题是 DataGrid,但您正在开发一个 Windows 应用程序,因此您将在那里使用的控件是 DataGridView...)

【讨论】:

  • 哦,对不起,那是我的错误。我正在使用 DataGridView。我已经看到你答案的第一个链接。我没有在那个代码中得到dataGridView1_CellClick。你能更新你的答案并给我一些描述吗?
【解决方案3】:

这是更好的答案:

您不能为 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);
  }
}

在这里找到: button click event in datagridview

【讨论】:

    【解决方案4】:

    这解决了我的问题。

    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 上的答案。
      【解决方案6】:

      假设例如 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,因为它不需要。

      【讨论】:

        【解决方案7】:

        这是我的代码 sn-p 触发点击事件并将值传递给另一个表单:

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

        【讨论】:

          【解决方案8】:

          好吧,我会咬人的。

          你需要做这样的事情——显然它都是元代码。

          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 后进入表单的构造函数中。
          • 你会从哪里得到按钮!?
          【解决方案9】:

          大多数投票的解决方案是错误的,因为不能在一行中使用几个按钮。

          最好的解决方案是以下代码:

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

          【讨论】:

            【解决方案10】:

            只需将 ToList() 方法添加到列表末尾,绑定到 datagridview 数据源:

            dataGridView1.DataSource = MyList.ToList();
            

            【讨论】:

              【解决方案11】:

              你可以试试这个,你不会太在意列的顺序。

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

              【讨论】:

                【解决方案12】:

                例如 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);
                                }
                

                问候:)

                【讨论】:

                  【解决方案13】:

                  如果有人正在使用 C#(或参见下面关于 VB.NET 的说明)并已达到这一点,但仍然卡住,请继续阅读。

                  约书亚的回答对我有所帮助,但不是全部。你会注意到彼得问“你从哪里得到按钮?”,但没有得到回答。

                  对我有用的唯一方法是执行以下操作之一来添加我的事件处理程序(在将我的 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 文档的“How to: Call an Event Handler in Visual Basic”中所述

                  【讨论】:

                    【解决方案14】:

                    您将在 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);
                    

                    【讨论】:

                      猜你喜欢
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 2011-10-16
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 2011-11-09
                      相关资源
                      最近更新 更多