DataGridView with Button Control - Delete Row
Asked Answered
M

1

9

I want a Delete button at the end of each row of DataGridView and by clicking that I want to remove the desired row from the binding list which is data source of my grid.

But I can't seem to do it I have created a button object in product class and instantiated it with the unique id to remove that object from list. but button is not showing in the row.

Screen shot

There are TextBoxes in the form and users can enter text, and when they press Add button, a new object of product is instantiated with the provided fields and then it is added to the BindingList.

Finally this list is bound to the DataGridView and details are shown in the grid. (I have done this part).

and at last by clicking save button the list is saved in the DB.

public class Product{
    public string Brand { get; set; }   
    public int ProductPrice { get; set; }
    public int Quantity { get; set; }

    public product(string brand,int productPrice, int quantity){   
        this.Brand = brand;
        this.ProductPrice = productPrice;
        this.Quantity = quantity;
    }   
}

public partial class MainForm: Form{
    .....
    BindingList<Product> lProd = new BindingList<Product>();
    private void btnAddProduct_Click(object sender, EventArgs e){
        string Brand = txtProBrand.Text;
        int Price = Convert.ToInt32(txtPrice.Text);
        int Quantity = Convert.ToInt32(txtQuantity.Text);

        Product pro = new Product(Brand, Price, Quantity);
        lProd.Add(pro);
        dataGridView1.DataSource = null;
        dataGridView1.DataSource = lProd;
    }
    .....
}
Menswear answered 5/11, 2015 at 11:29 Comment(3)
I think this has been answered before. https://mcmap.net/q/568382/-how-to-add-a-button-to-a-column-in-the-datagridviewFalconiform
i can't seem to do it in a list. i can add a button to datatable. how to do that in the list??Menswear
If by list you mean your bindinglist then the answer is that you don't want to do that :) Your grid is bound to your Bindinglist of T, and the columns reflect the properties in your object of type T, and you don't want a "delete" property in your object - wich doesn't make much sense. Bind the datagridviwe to your list (like before) and then manually add a column with a delete-button, like this answer suggests.Noblenobleman
P
27

To show a button on DataGridView rows, you should add a DataGridViewButtonColumn to columns of your grid. Here is some common tasks which you should know when using button column:

  • Add Button Column to DataGridView
  • Show Image on Button
  • Set Text of Button
  • Handle Click Event of Button

Add Button Column to DataGridView

To show a button on each row of your grid, you can add a DataGridViewButtonColumn to columns of your grid programmatically or using designer:

var deleteButton=new DataGridViewButtonColumn();
deleteButton.Name="dataGridViewDeleteButton";
deleteButton.HeaderText="Delete";
deleteButton.Text="Delete";
deleteButton.UseColumnTextForButtonValue=true;
this.dataGridView1.Columns.Add(deleteButton);

Show Image on Button

If you prefer to draw image on button, you should have an image in a resource and then handle CellPainting event of your grid:

void dataGridView1_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
{
    if (e.RowIndex == dataGridView1.NewRowIndex || e.RowIndex < 0)
        return;

    if (e.ColumnIndex == dataGridView1.Columns["dataGridViewDeleteButton"].Index)
    {
        var image = Properties.Resources.DeleteImage; //An image
        e.Paint(e.CellBounds, DataGridViewPaintParts.All);
        var x = e.CellBounds.Left + (e.CellBounds.Width - image.Width) / 2;
        var y = e.CellBounds.Top + (e.CellBounds.Height - image.Height) / 2;
        e.Graphics.DrawImage(image, new Point(x, y));

        e.Handled = true;
    }
}

Set Text of Button

You can use either of these options:

You can set Text property of your DataGridViewButtonColumn and also set its UseColumnTextForButtonValue to true, this way the text will display on each cells of that column.

deleteButton.Text="Delete";
deleteButton.UseColumnTextForButtonValue=true;

Also you can use Value property of cell:

this.dataGridView1.Rows[1].Cells[0].Value = "Some Text";

Also as another option, you can handle CellFormatting event of your grid. This way may be useful when you want to set different texts for buttons.

void dataGridView1_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
    //If this is header row or new row, do nothing
    if (e.RowIndex < 0 || e.RowIndex == this.dataGridView1.NewRowIndex)
        return;

    //If formatting your desired column, set the value
    if (e.ColumnIndex=this.dataGridView1.Columns["dataGridViewDeleteButton"].Index)
    {
        e.Value = "Delete";
    }
}

Handle Click Event of Button

To hanlde clicks on button, you can handle CellClick or CellContentClick event of your grid. Both events fires by click and by pressing Space key.

void dataGridView_CellClick(object sender, DataGridViewCellEventArgs e)
{
    //if click is on new row or header row
    if( e.RowIndex == dataGridView1.NewRowIndex || e.RowIndex < 0)
        return;

    //Check if click is on specific column 
    if( e.ColumnIndex  == dataGridView1.Columns["dataGridViewDeleteButton"].Index)
    {
        //Put some logic here, for example to remove row from your binding list.
        //yourBindingList.RemoveAt(e.RowIndex);

        // Or
        // var data = (Product)dataGridView1.Rows[e.RowIndex].DataBoundItem;
        // do something 
    }
}

Get data of the record on Click event

You have e.RowIndex, then you can get the data behind the row:

 var data = (Product)dataGridView1.Rows[e.RowIndex].DataBoundItem;
// then you can get data.Id, data.Name, data.Price, ...

You need to cast it to the data type of the recore, for example let's say Product.

If the data binding has been setup to use a DataTable, the the type to cast is DataRowView.

You can also use dataGridView1.Rows[e.RowIndex].Cells[some cell index].Value to get value of a specific cell, however DataBoundItem makes more sense.

Note

  • As mentioned by Ivan in comments, when you use BindingList you don't need to set datasource of grid to null and back to binding list with every change. The BindingList itself reflects changes to your DataGridView.
Pinworm answered 5/11, 2015 at 16:21 Comment(3)
Hi Reza. I was going to answer this, but noticed you already did. Could you include in your answer advice to remove the lines that set DataSource to null and then to binding list on every add to the binding list. Cheers.Interrupted
Hi, Thank you for your comment Ivan, feel free to edit my answer and make it more useful :)Pinworm
Thank you, but I'm not so good in explanations like you :-) The code I mentioned, in addition of being redundant and inefficient, will require OP to recreate the column in question in case AutoGenerateColumns is true, which I bet is.Interrupted

© 2022 - 2024 — McMap. All rights reserved.