• How to delete a Row from GridView with Client-Side Confirmation

    Posted on June 14, 2012 by in ASP.NET, C#, Dotnet

    In this article, I am going to explain how to delete a row from GridView and also to show a confirm popup before proceeding with the delete operation.

    Database Connection:
    I am using AdventureWorks database for this example. Open web.config and add following entry to connection strings element

    <add name="Sql" connectionString="Data Source=<SERVERNAME>;
         Initial Catalog= AdventureWorks;User=testuser;Password=testuser;"
         providerName="System.Data.SqlClient"/>
    

    DataSource
    The SqlDataSource data source control is simply a control that represents data in an SQL relational database to data-bound controls. You can use the SqlDataSource control in conjunction with a data-bound control such as Dropdownlist, gridview etc to retrieve data from a relational database and to display, edit, and sort data on a Web page with little or no code. The ConnectionString property of the SqlDataSource control specifies how to connect to the database. This property can be a hard-coded connection string or can point to a connection string in a Web.config file as shown in the code given above. The SelectCommand property specifies the SQL statement to execute to retrieve the data.

    <asp:SqlDataSource ID="sqlDSProducts" runat="server"
        ConnectionString="<%$ ConnectionStrings:Sql %>"
        SelectCommand="Select top 10 * from Production.Product order by ProductID desc"/>
    

    Page Design
    We are interested in ProductID, ProductName , ProductNumber, ListPrice product attributes.  In order to bind the SQLDataSource created above to the grid, set the “DataSourceID” property of the GridView to “sqlDSProducts” (ID property value of SQLDataSource).

    <asp:gridview id="gvProducts"
      autogeneratecolumns="False
      runat="server" DataKeyNames="ProductID" DataSourceID="sqlDSProducts"
      CssClass="GridViewStyle"
      OnRowCreated="gvProducts_RowCreated" OnRowCommand="gvProducts_RowCommand">
      <RowStyle CssClass="RowStyle" />
      <FooterStyle CssClass="RowStyle" />
      <SelectedRowStyle CssClass="SelectedRowStyle" />
      <HeaderStyle CssClass="HeaderStyle" />
      <AlternatingRowStyle CssClass="AltRowStyle" />
        <Columns>
            <asp:BoundField DataField="ProductID" HeaderText="Product ID"/>
            <asp:BoundField DataField="ProductNumber" HeaderText="Product Number"/>
            <asp:BoundField DataField="Name" HeaderText="Product Name"/>
            <asp:BoundField DataField="ListPrice" HeaderText="Price" DataFormatString="{0:C}"/>
            <asp:TemplateField>
                       <ItemTemplate>
                           <asp:LinkButton ID="lkDelete" runat="server"
                                OnClientClick = 'return confirm("Are you sure you want to delete this entry?");'
                                CommandName="DeleteProduct" Text="Delete"/>
                       </ItemTemplate>
                    </asp:TemplateField>
        </Columns>
    </asp:gridview>
    
    Name Description
    OnRowCommand = “ProductsView_RowCommand” when a button is clicked in the GridView control, ProductsView_RowCommand is called.
    OnRowCreated=”ProductsView_Created” RowCreated event is raised when each row in the GridView control is created.
    DataKeyNames Gets or sets an array that contains the names of the primary key fields for the items displayed in a GridView control.
    BoundField Displays the value of a field in a data source. This is the default column type of the GridView control.
    BoundField -> DataField Gets or sets the name of the data field to bind to the BoundField object.
    BoundField -> HeaderText Gets or sets the text that is displayed in the header of a data control
    BoundField -> DataFormatString Gets or sets the string that specifies the display format for the value of the field.
    ItemStyle Gets the style of any text-based content displayed by a data control field.
    <asp:LinkButton ID=”lnkDelete” runat=”server” CommandName=”DeleteProduct” Text=”Delete” /> Command name is set to “DeleteProduct” explicitly as we don’t want to event to be bubbled up to sqlDsProducts SqlDataSoure control. We would like to handle delete on our own.  I will discuss more about this later.
    TemplateField Used TemplateField to display custom content for each record displayed.
    TemplateField -> ItemTemplate Use the ItemTemplate property to specify the custom content displayed for the items in a TemplateField object. Define the content by creating a template that specifies how the items are rendered.

    For every row created in the GridVIew, RowCreated event is raised. Here in the event handler, we can perform actions such as adding/modifying content of the row. In this example, we store the index of the row in the CommandArgument property of a LinkButton control contained in the row. This information will be used when user clicks on the “Delete” button.

    protected void gvProducts_RowCreated(object sender, GridViewRowEventArgs e)
    {
        if (e.Row.RowType == DataControlRowType.DataRow)
        {
            LinkButton buttonSelect = (LinkButton)e.Row.Cells[0].FindControl("lkDelete");
            buttonSelect.CommandArgument = e.Row.RowIndex.ToString();
        }
    }
    

    When the user clicks on the “Delete” link button, OnRowCommand is raised on the server side. However before the page is submitted, we show a JAVASCRIPT POP-UP. Only if the user hits on the “OK” button page will be posted back. If the user clicks on “OK”, in the OnRowCommand  event handler, we initially check if it is indeed “Delete” button that caused the event to raise. We get the row index from the command source property of the linkbutton. Once we have the rowindex, we call RemoveProduct method to delete the product. You would notice that the command name of the Delete button is set to “DeleteProduct” explicitly. This is needed as we don’t want sqlDSProducts SqlDataSource control to try to handle the delete operation.

    protected void gvProducts_RowCommand(object sender, GridViewCommandEventArgs e)
    {
        // If multiple buttons are used, use the
        // CommandName property to determine if "DeleteProduct" button was clicked. 
        if (e.CommandName.Equals("DeleteProduct"))
        {
            // Convert the row index stored in the CommandArgument
            // property to an Integer.
            int index = Convert.ToInt32(e.CommandArgument);
            GridViewRow row = gvProducts.Rows[index];
    
            //fetch product attributes from current row
            string productID = gvProducts.DataKeys[index].Value.ToString();
            string productName = row.Cells[1].Text;
            
            //delete product
            RemoveProduct(productID, productName);                            
        }            
    }
    

    In the RemoveProduct method, we use ADO.NET API to fire a delete query to delete the product from the database. We display the deleted product information to the user in a message label (lblMessage).

    private void RemoveProduct(string productID, string productName)
    {            
        //fetch the connection string from web.config
        string connString = ConfigurationManager.ConnectionStrings["Sql"].ConnectionString;
    
        //SQL statement to delete from products
        string sql = String.Format(@"Delete from Production.Product where ProductID = ({0})", productID);
    
        using (SqlConnection conn = new SqlConnection(connString))
        {
            conn.Open();
            //Initialize command object
            using (SqlCommand cmd = new SqlCommand(sql, conn))
            {
                cmd.ExecuteNonQuery();
            }
        }
        lblMessage.Text = "Following product was deleted";
        lblMessage.Text += String.Format("<br/> ProductID: {0}; ProductName: {1}", productID, productName);
        
    }
    

    NOTE: Production.Product in AdventureWorks table has dependencies to other tables. Since the focus of this article is not about cascaded deletes, I simple populated some dummy data into that table by running following query.

    INSERT INTO [AdventureWorks].[Production].[Product]
               ([Name],
               [ProductNumber],
               [MakeFlag],[FinishedGoodsFlag],[Color],[SafetyStockLevel],[ReorderPoint]
               ,[StandardCost], [ListPrice],[Size],[SizeUnitMeasureCode]
               ,[WeightUnitMeasureCode],[Weight],[DaysToManufacture],[ProductLine]
               ,[Class],[Style],[ProductSubcategoryID],[ProductModelID],[SellStartDate]
               ,[SellEndDate],[DiscontinuedDate], [rowguid],[ModifiedDate])
         
         SELECT [Name] + ' ' + Convert(varchar, ABS(CAST(NEWID() AS binary(6)) %1000) + 1)
               ,[ProductNumber] + ' ' + Convert(varchar, ABS(CAST(NEWID() AS binary(6)) %1000) + 1)
               [MakeFlag],[FinishedGoodsFlag],[Color],[SafetyStockLevel],[ReorderPoint]
               ,[StandardCost],[ListPrice],[Size],[SizeUnitMeasureCode]
               ,[WeightUnitMeasureCode],[Weight],[DaysToManufacture],[ProductLine]
               ,[Class],[Style],[ProductSubcategoryID],[ProductModelID],[SellStartDate]
               ,[SellEndDate],[DiscontinuedDate],[rowguid],[ModifiedDate]
         FROM Production.Product WHERE ProductID = 1
    

    Run the application and top 10 products ordered by product (desc) are loaded as shown below:

    Click on “Delete” button and you would see a confirmation pop-up as shown below:

    Clicking “OK” on the pop-up will delete the product from the database. You would also see the details of the product that is deleted.

    Be Sociable, Share!
      Post Tagged with , ,

    Written by

    Software architect with over 10 years of proven experience in designing & developing n-tier and web based software applications, for Finance, Telecommunication, Manufacturing, Internet and other Commercial industries. He believes that success depends on one's ability to integrate multiple technologies to solve a simple as well as complicated problem.

    View all articles by

    Email : [email protected]

    Leave a Reply