How to handle click event in Button Column in Datagridview?

C#.NetWinformsDatagridview

C# Problem Overview


I am developing a windows application using C#. I am using DataGridView to display data. I have added a button column in that. I want to know how can I handle click event on that button in DataGridView.

C# Solutions


Solution 1 - C#

You've added a button to your DataGridView and you want to run some code when it's clicked.

Easy peasy - just follow these steps:

Don'ts

First, here's what NOT to do:

I would avoid the suggestions in some of the other answers here and even provided by the documentation at MSDN to hardcode the column index or column name in order to determine if a button was clicked. The click event registers for the entire grid, so somehow you need to determine that a button was clicked, but you should not do so by assuming that your button lives in a particular column name or index... there's an easier way...

Also, be careful which event you want to handle. Again, the documentation and many examples get this wrong. Most examples handle the CellClick event which will fire:

> when any part of a cell is clicked.

...but will also fire whenever the row header is clicked. This necessitates adding extra code simply to determine if the e.RowIndex value is less than 0

Instead handle the CellContentClick which only occurs:

>when the content within a cell is clicked

For whatever reason, the column header is also considered 'content' within a cell, so we'll still have to check for that below.

Dos

So here's what you should do:

First, cast the sender to type DataGridView to expose it's internal properties at design time. You can modify the type on the parameter, but that can sometimes make adding or removing handlers tricky.

Next, to see if a button was clicked, just check to make sure that the column raising the event is of type DataGridViewButtonColumn. Because we already cast the sender to type DataGridView, we can get the Columns collection and select the current column using e.ColumnIndex. Then check if that object is of type DataGridViewButtonColumn.

Of course, if you need to distinguish between multiple buttons per grid, you can then select based on the column name or index, but that shouldn't be your first check. Always make sure a button was clicked first and then handle anything else appropriately. In most cases where you only have a single button per grid, you can jump right off to the races.

Putting it all together:

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

Update 1 - Custom Event

If you wanted to have a little bit of fun, you can add your own event to be raised whenever a button is clicked on the DataGrid. You can't add it to the DataGrid itself, without getting messy with inheritance etc., but you can add a custom event to your form and fire it when appropriate. It's a little more code, but the upside is that you've separated out what you want to do when a button is clicked with how to determine if a button was clicked.

Just declare an event, raise it when appropriate, and handle it. It will look like this:

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

Update 2 - Extended Grid

What would be great is if we were working with a grid that just did these things for us. We could answer the initial question easily: you've added a button to your DataGridView and you want to run some code when it's clicked. Here's an approach that extends the DataGridView. It might not be worth the hassle of having to deliver a custom control with every library, but at least it maximally reuses the code used for determining if a button was clicked.

Just add this to your assembly:

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

That's it. Never touch it again. Make sure your DataGrid is of type DataGridViewExt which should work exactly the same as a DataGridView. Except it will also raise an extra event that you can handle like this:

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

Solution 2 - C#

That's answered fully here for WinForms: DataGridViewButtonColumn Class

and here: How to: Respond to Button Events in a GridView Control

for Asp.Net depending on the control you're actually using. (Your question says DataGrid, but you're developing a Windows app, so the control you'd be using there is a DataGridView...)

Solution 3 - C#

Here's the better answer:

You can't implement a button clicked event for button cells in a DataGridViewButtonColumn. Instead, you use the DataGridView's CellClicked event and determine if the event fired for a cell in your DataGridViewButtonColumn. Use the event's DataGridViewCellEventArgs.RowIndex property to find out which row was clicked.

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

found here: https://stackoverflow.com/questions/7286352/button-click-event-in-datagridview

Solution 4 - C#

This solves my problem.

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

Solution 5 - C#

A bit late to the table here, but in c# (vs2013) you don't need to use column names either, in fact a lot of the extra work that some people propose is completely unnecessary.

The column is actually created as an member of the container (the form, or usercontrol that you've put the DataGridView into). From the designer code (the stuff you're not supposed to edit except when the designer breaks something), you'd see something like:

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;

So in the CellContentClick handler, apart from ensuring that the row index is not 0, you just need to check whether the clicked column is in fact the one you want by comparing object references:

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

Note that the beauty of this is that any name changes will be caught by the compiler. If you index with a text name that changes, or that you capitalize incorrectly, you're bound for runtime issues. Here you actually use the name of an object, that the designer creates based on the name you supplied. But any mismatch will be brought to your attention by the compiler.

Solution 6 - C#

Assuming for example DataGridView has columns as given below and its data bound items are of type PrimalPallet you can use solution given below.

enter image description here

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.
		}
	}
}

It's safer to access columns directly rather than using dataGridView1.Columns["MyColumnName"] and there is no need to parse sender to the DataGridView as it's not needed.

Solution 7 - C#

Here is my code snippet to fire the click event and pass the value to another form :

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

        }
    }

Solution 8 - C#

fine, i'll bite.

you'll need to do something like this -- obviously its all metacode.

button.Click += new ButtonClickyHandlerType(IClicked_My_Button_method)

that "hooks" the IClicked_My_Button_method method up to the button's Click event. Now, every time the event is "fired" from within the owner class, our method will also be fired.

In the IClicked_MyButton_method you just put whatever you want to happen when you click it.

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.
}

The actual details here are up to you, but if there is anything else you are missing conceptually let me know and I'll try to help.

Solution 9 - C#

Most voted solution is wrong, as cannot work with few buttons in one row.

Best solution will be the following code:

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

Solution 10 - C#

You can try this one, you wouldn't care much about the ordering of the columns.

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

Solution 11 - C#

For example for ClickCell Event in Windows Forms.

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

Regards :)

Solution 12 - C#

In case someone is using C# (or see Note about VB.NET below) and has reached this point, but is still stuck, please read on.

Joshua's answer helped me, but not all the way. You will notice Peter asked "Where would you get the button from?", but was unanswered.

The only way it worked for me was to do one of the following to add my event hander (after setting my DataGridView's DataSource to my DataTable and after adding the DataGridViewButtonColumn to the DataGridView):

Either:

dataGridView1.CellClick += new DataGridViewCellEventHandler(dataGridView1_CellClick);

or:

dataGridView1.CellContentClick += new DataGridViewCellEventHandler(dataGridView1_CellContentClick);

And then add the handler method (either dataGridView1_CellClick or dataGridView1_CellContentClick) shown in the various answers above.

Note: VB.NET is different from C# in this respect, because we can simply add a Handles clause to our method's signature or issue an AddHandler statement as described in the Microsoft doc's "How to: Call an Event Handler in Visual Basic"

Solution 13 - C#

You will add button column like this in your dataGridView

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


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

Then you can add some actions inside cell click event. I found this is easiest way of doing it.

    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.
         }


    }

I found that Cell Click event is automatically subscribed often. So I did not need this code below. However, if your cell click event is not subscribed, then add this line of code for your dataGridView.

     this.dataGridView.CellClick += new System.Windows.Forms.DataGridViewCellEventHandler(this.dataGridView_CellClick);

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionHimadriView Question on Stackoverflow
Solution 1 - C#KyleMitView Answer on Stackoverflow
Solution 2 - C#DavidView Answer on Stackoverflow
Solution 3 - C#TechStuffBCView Answer on Stackoverflow
Solution 4 - C#HimadriView Answer on Stackoverflow
Solution 5 - C#ArunasView Answer on Stackoverflow
Solution 6 - C#RyfciaView Answer on Stackoverflow
Solution 7 - C#sh.e.salhView Answer on Stackoverflow
Solution 8 - C#Joshua EvensenView Answer on Stackoverflow
Solution 9 - C#AndrewView Answer on Stackoverflow
Solution 10 - C#JL DajoyagView Answer on Stackoverflow
Solution 11 - C#Diego Mauricio GuerreroView Answer on Stackoverflow
Solution 12 - C#clairestrebView Answer on Stackoverflow
Solution 13 - C#auto9817View Answer on Stackoverflow