Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

ASP.NET Gridview Editable in Web Forms using Bootstrap 4

0.00/5 (No votes)
30 Jul 2019 3  
This post describes implementing ASP.NET Editable Gridview using Bootstrap 4

Introduction

My first article is ASP.NET Gridview in Web Forms using Bootstrap 4. This is the second article about ASP.NET Gridview Editable in Web Forms using Bootstrap 4, connect to SQL Server with Microsoft.ApplicationBlocks.Data. We are going to build a new database, table, stored procedures, and ASP.NET website with other available download software, and write less codes for editable gridview by using Bootstrap.

Background

My first article about ASP.NET Gridview in Web Forms using Bootstrap 4 can be found here. This a based on an article here, but this article combined the editable for ASP.NET Gridview while using Bootstrap 4 with downloadable example.

Software Requirement Before Using the Code

Before using the code, we need to prepare a database, table, stored procedure with a SQL server, create a new website with other available for download softwares.

1. Create a New ASP.NET Empty Web Site Project with Files

  • Use the Microsoft Visual Studio to create a new ASP.NET Empty Web Site called MyContact
  • In Visual Studio, add a new folder called bootstrap to the MyContact solution
  • In Visual Studio, add 1 new Web Form Default to the MyContact solution
  • In Visual Studio, add new folder SQL, add 1 new text file named 01.00.00.SqlDataProvider
  • In Visual Studio, right click at MyContact solution, add 4 new classes: DataProvider.cs, ContactController.cs, ContactInfo.cs, Helper.cs.
  • In Visual Studio, click on Tools menu, select NuGet Package Manager, select Manage NuGet Packages for Solution, click on Browse and search for Microsoft.ApplicationBlocks.Data, then install it.

After completing all the steps above, the MyContact project will be displayed as shown below:

2. Add Bootstrap Files to ASP.NET Web Site project

  • Download bootstrap’s Compiled CSS and JS files from http://getbootstrap.com.
  • Un-zip the downloaded bootstrap file bootstrap-4.0.0-dist.zip.
  • Copy the folders css and js and paste them to the folder bootstrap of MyContact solution.

3. Add Template Files using Bootstrap to ASP.NET Web Site Project

  • Download Bootstrap 4 admin dashboard template from GitHub puikinsh/sufee-admin-dashboard. (Click a button Clone or Download, then click a button Download ZIP)
  • Un-zip the downloaded sufee-admin-dashboard-master.zip.
  • Copy all folders and files from folder sufee-admin-dashboard-master, and paste them to the folder bootstrap of MyContact solution

After finishing steps 2 and 3 above, the bootstrap folder in MyContact solution will look like the image below:

4. Create New Database, Tables, and Stored Procedures in SQL Server

We will use the Microsoft SQL Server Management Studio to run queries to create new Database, Tables, and Stored Procedures for our application. The file containing the queries is 01.00.00.SqlDataProvider.

/************************************************************/
/*****              SqlDataProvider                     *****/
/*****                                                  *****/
/*****                                                  *****/
/***** Note: To manually execute this script you must   *****/
/*****       perform a search and replace operation     *****/
/*****                                                  *****/
/************************************************************/
SET NOCOUNT ON
GO

USE master
GO
if exists (select * from sysdatabases where name='MyContact')
  drop database MyContact
go

DECLARE @device_directory NVARCHAR(520)
SELECT @device_directory = _
       SUBSTRING(filename, 1, CHARINDEX(N'master.mdf', LOWER(filename)) - 1)
FROM master.dbo.sysaltfiles WHERE dbid = 1 AND fileid = 1

EXECUTE (N'CREATE DATABASE MyContact
  ON PRIMARY (NAME = N''MyContact'', _
              FILENAME = N''' + @device_directory + N'mycontact.mdf'')
  LOG ON (NAME = N''MyContact_log'',  FILENAME = N''' + _
              @device_directory + N'mycontact.ldf'')')
go

set quoted_identifier on
GO

/* Set DATEFORMAT so that the date strings are interpreted correctly regardless of
   the default DATEFORMAT on the server.
*/
SET DATEFORMAT mdy
GO

use "MyContact"
go

if exists (select * from sysobjects _
           where id = object_id('dbo.Contacts') and sysstat & 0xf = 3)
 drop table "dbo"."Contacts"
GO
CREATE TABLE "Contacts" (
 "ContactId"  int IDENTITY (1, 1) NOT NULL,
 "FirstName"  nvarchar (20) NOT NULL,
 "LastName"  nvarchar (20) NOT NULL,
 "Address"  nvarchar (60) NULL,
 "City"   nvarchar (15) NULL,
 "Region"  nvarchar (15) NULL,
 "PostalCode" nvarchar (10) NULL,
 "Country"  nvarchar (15) NULL,
 "Phone"   nvarchar (24) NULL,
 "EmailAddress" nvarchar (255) NULL,
 "CreatedDate" datetime NOT NULL,
 "UpdatedDate" datetime NULL,
 CONSTRAINT "PK_Contacts" PRIMARY KEY  CLUSTERED
 (
  "ContactId"
 )
)
GO

/************************************************************/
/*****              SqlDataProvider                     *****/
/************************************************************/
/** Drop Existing Contact Stored Procedures **/

if exists (select * from dbo.sysobjects where id = object_id(N'[GetContact]') _
           and OBJECTPROPERTY(id, N'IsProcedure') = 1)
 drop procedure GetContact
GO

if exists (select * from dbo.sysobjects where id = object_id(N'[AddContact]') _
           and OBJECTPROPERTY(id, N'IsProcedure') = 1)
 drop procedure AddContact
GO

if exists (select * from dbo.sysobjects where id = object_id(N'[UpdateContact]') _
           and OBJECTPROPERTY(id, N'IsProcedure') = 1)
 drop procedure UpdateContact
GO

if exists (select * from dbo.sysobjects where id = object_id(N'[DeleteContact]') _
           and OBJECTPROPERTY(id, N'IsProcedure') = 1)
 drop procedure DeleteContact
GO

/** Create Contact Stored Procedures **/

create procedure GetContact

 @ContactId  int = NULL

as

DECLARE @sql        nvarchar(MAX),
  @paramlist  nvarchar(MAX)

SELECT @sql = 'SELECT ContactId,
 ContactId,
 LastName,
 FirstName,
 Address,
 City,
 Region,
 PostalCode,
 Country,
 Phone,
 EmailAddress,
 CreatedDate,
 UpdatedDate
from Contacts with (nolock)
where  1 = 1'

IF @ContactId IS NOT NULL AND @ContactId > 0
   SELECT @sql = @sql + ' AND ContactId = @xContactId'

/* IF @debug = 1 */
/*    PRINT @sql */

SELECT @sql = @sql + ' order by LastName'

SELECT @paramlist = '@xContactId  int'

EXEC sp_executesql @sql, @paramlist,
 @ContactId

GO

create procedure AddContact

 @FirstName  nvarchar (20),
 @LastName  nvarchar (20),
 @Address  nvarchar (60),
 @City   nvarchar (15),
 @Region   nvarchar (15),
 @PostalCode  nvarchar (10),
 @Country  nvarchar (15),
 @Phone   nvarchar (24),
 @EmailAddress nvarchar (255)

as

insert into Contacts (
 FirstName,
 LastName,
 Address,
 City,
 Region,
 PostalCode,
 Country,
 Phone,
 EmailAddress,
 CreatedDate
)
values (
 @FirstName,
 @LastName,
 @Address,
 @City,
 @Region,
 @PostalCode,
 @Country,
 @Phone,
 @EmailAddress,
 getdate()
)

--return the ID of the tranaction back so we can create a TransactionID    
Select SCOPE_IDENTITY()

GO

create procedure UpdateContact

 @ContactId  int,
 @FirstName  nvarchar (20),
 @LastName  nvarchar (20),
 @Address  nvarchar (60),
 @City   nvarchar (15),
 @Region   nvarchar (15),
 @PostalCode  nvarchar (10),
 @Country  nvarchar (15),
 @Phone   nvarchar (24),
 @EmailAddress nvarchar (255)

as

update Contacts
set 
 FirstName  = @FirstName,
 LastName  = @LastName,
 Address   = @Address,
 City   = @City,
 Region   = @Region,
 PostalCode  = @PostalCode,
 Country   = @Country,
 Phone   = @Phone,
 EmailAddress = @EmailAddress,
 UpdatedDate  = getdate()
where ContactId = @ContactId

GO

create procedure DeleteContact

 @ContactId int

as

delete
from   Contacts
where ContactId = @ContactId

GO

/************************************************************/
/*****              SqlDataProvider                     *****/
/************************************************************/
set quoted_identifier on
go
set identity_insert "Contacts" on
go
ALTER TABLE "Contacts" NOCHECK CONSTRAINT ALL
go
INSERT "Contacts"("ContactID","LastName","FirstName","Address","City","Region",_
                  "PostalCode","Country","Phone","EmailAddress","CreatedDate") _
                  VALUES(1,'Davolio','Nancy','507 - 20th Ave. E. Apt. 2A','Seattle','WA',_
                  '98122','USA','(206) 555-9857','Nancy@mycontact.com',GETDATE())
GO
INSERT "Contacts"("ContactID","LastName","FirstName","Address","City","Region",_
                  "PostalCode","Country","Phone","EmailAddress","CreatedDate") _
                  VALUES(2,'Fuller','Andrew','908 W. Capital Way','Tacoma','WA',_
                  '98401','USA','(206) 555-9482','Andrew@mycontact.com',GETDATE())
GO
INSERT "Contacts"("ContactID","LastName","FirstName","Address","City","Region",_
                  "PostalCode","Country","Phone","EmailAddress","CreatedDate") _
                  VALUES(3,'Leverling','Janet','722 Moss Bay Blvd.','Kirkland','WA',_
                  '98033','USA','(206) 555-3412','Janet@mycontact.com',GETDATE())
GO
INSERT "Contacts"("ContactID","LastName","FirstName","Address","City","Region",_
                  "PostalCode","Country","Phone","EmailAddress","CreatedDate") _
                  VALUES(4,'Peacock','Margaret','4110 Old Redmond Rd.','Redmond','WA',_
                  '98052','USA','(206) 555-8122','Margaret@mycontact.com',GETDATE())
GO
INSERT "Contacts"("ContactID","LastName","FirstName","Address","City","Region",_
                  "PostalCode","Country","Phone","EmailAddress","CreatedDate") _
                  VALUES(5,'Buchanan','Steven','14 Garrett Hill','London',NULL,_
                  'SW1 8JR','UK','(71) 555-4848','Steven@mycontact.com',GETDATE())
GO
INSERT "Contacts"("ContactID","LastName","FirstName","Address","City","Region",_
                  "PostalCode","Country","Phone","EmailAddress","CreatedDate") _
                  VALUES(6,'Suyama','Michael','Coventry House Miner Rd.','London',NULL,_
                  'EC2 7JR','UK','(71) 555-7773','Michael@mycontact.com',GETDATE())
GO
INSERT "Contacts"("ContactID","LastName","FirstName","Address","City","Region",_
                  "PostalCode","Country","Phone","EmailAddress","CreatedDate") _
                  VALUES(7,'King','Robert','Edgeham Hollow Winchester Way','London',NULL,_
                  'RG1 9SP','UK','(71) 555-5598','Robert@mycontact.com',GETDATE())
GO
INSERT "Contacts"("ContactID","LastName","FirstName","Address","City","Region",_
                  "PostalCode","Country","Phone","EmailAddress","CreatedDate") _
                  VALUES(8,'Callahan','Laura','4726 - 11th Ave. N.E.','Seattle','WA',_
                  '98105','USA','(206) 555-1189','Laura@mycontact.com',GETDATE())
GO
INSERT "Contacts"("ContactID","LastName","FirstName","Address","City","Region",_
                  "PostalCode","Country","Phone","EmailAddress","CreatedDate") _
                  VALUES(9,'Dodsworth','Anne','7 Houndstooth Rd.','London',NULL,_
                  'WG2 7LT','UK','(71) 555-4444','Anne@mycontact.com',GETDATE())
go
set identity_insert "Contacts" off
go
ALTER TABLE "Contacts" CHECK CONSTRAINT ALL
go

The ContactInfo.cs will keep contact information. We have FullName and FullAddress to be displayed at the Gridview. The DisplayAddress will be displayed at the Detail Modal.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

/// <summary>
/// Summary description for ContactInfo
/// </summary>
public class ContactInfo
{
    //
    // TODO: Add constructor logic here
    //
    public int ContactId { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Address { get; set; }
    public string City { get; set; }
    public string Region { get; set; }
    public string PostalCode { get; set; }
    public string Country { get; set; }
    public string Phone { get; set; }
    public string EmailAddress { get; set; }
    public DateTime CreatedDate { get; set; }
    public DateTime UpdatedDate { get; set; }
    public string FullName
    {
        get
        {
            return FirstName + " " + LastName;
        }
    }
    public string FullAddress
    {
        get
        {
            return Address + ", " + City + ", " + Region + " " + PostalCode + " - " + Country;
        }
    }
    public string DisplayAddress
    {
        get
        {
            return Address + "<br />" + City + ", " + Region + " " + _
                                        PostalCode + "<br />" + Country;
        }
    }
}

The Helper.cs will convert objects as shown below. We convert DataTable to List of Objects to manage data fields.

using Microsoft.ApplicationBlocks.Data;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Reflection;
using System.Web;

/// <summary>
/// Summary description for Helper
/// </summary>
public static class Helper
{
    #region Helper

    /// <summary>
    /// Converts a DataTable to a list with generic objects
    /// </summary>
    /// <typeparam name="T">Generic object</typeparam>
    /// <param name="table">DataTable</param>
    /// <returns>List with generic objects</returns>
    public static List<T> DataTableToList<T>(this DataTable table) where T : class, new()
    {
        try
        {
            List<T> list = new List<T>();

            foreach (var row in table.AsEnumerable())
            {
                T obj = new T();

                foreach (var prop in obj.GetType().GetProperties())
                {
                    try
                    {
                        PropertyInfo propertyInfo = obj.GetType().GetProperty(prop.Name);
                        propertyInfo.SetValue(obj, Convert.ChangeType_
                               (row[prop.Name], propertyInfo.PropertyType), null);
                    }
                    catch
                    {
                        continue;
                    }
                }
                list.Add(obj);
            }
            return list;
        }
        catch
        {
            return null;
        }
    }

    /// <summary>
    /// Convert a List{T} to a DataTable.
    /// </summary>
    public static DataTable ListToDataTable<T>(List<T> items)
    {
        var tb = new DataTable(typeof(T).Name);

        PropertyInfo[] props = typeof(T).GetProperties_
                               (BindingFlags.Public | BindingFlags.Instance);

        foreach (PropertyInfo prop in props)
        {
            Type t = GetCoreType(prop.PropertyType);
            tb.Columns.Add(prop.Name, t);
        }

        foreach (T item in items)
        {
            var values = new object[props.Length];

            for (int i = 0; i < props.Length; i++)
            {
                values[i] = props[i].GetValue(item, null);
            }

            tb.Rows.Add(values);
        }
        return tb;
    }

    /// <summary>
    /// Determine of specified type is nullable
    /// </summary>
    public static bool IsNullable(Type t)
    {
        return !t.IsValueType || _
              (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>));
    }

    /// <summary>
    /// Return underlying type if type is Nullable otherwise return the type
    /// </summary>
    public static Type GetCoreType(Type t)
    {
        if (t != null && IsNullable(t))
        {
            if (!t.IsValueType)
            {
                return t;
            }
            else
            {
                return Nullable.GetUnderlyingType(t);
            }
        }
        else
        {
            return t;
        }
    }

    #endregion
}

The DataProvider.cs will get data from SQL Server to List of Objects for our application. The Add New Record, Update Record, and Delete Record will call Stored Procedures.

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Web;
using Microsoft.ApplicationBlocks.Data;

/// <summary>
/// Summary description for DataProvider
/// </summary>
///
public abstract class DataProvider
{
    public static string ConnectionString = "Data Source=localhost;
                  Initial Catalog=ChangeMe;User ID=sa;Password=ChangeMe";

    //get { return DatabaseOwner + ObjectQualifier + ModuleQualifier; }
    private static string NamePrefix
    {
        get { return ""; }
    }

    #region Request Type
    public static List<ContactInfo> GetAllContacts()
    {
        DataSet objDS = SqlHelper.ExecuteDataset
             (ConnectionString, CommandType.StoredProcedure, NamePrefix + "GetContact",
            new SqlParameter("@ContactId", null));
        return Helper.DataTableToList<ContactInfo>(objDS.Tables[0]);
    }

    public static ContactInfo GetContact(int ContactId)
    {
        DataSet objDS = SqlHelper.ExecuteDataset(ConnectionString, 
                        CommandType.StoredProcedure, NamePrefix + "GetContact",
            new SqlParameter("@ContactId", ContactId));
        return Helper.DataTableToList<ContactInfo>(objDS.Tables[0])[0];
    }

    public static int AddContact(ContactInfo objInfo)
    {
        return Convert.ToInt32(SqlHelper.ExecuteScalar
                              (ConnectionString, NamePrefix + "AddContact",
            new SqlParameter("@FirstName", objInfo.FirstName),
            new SqlParameter("@LastName", objInfo.LastName),
            new SqlParameter("@Address", objInfo.Address),
            new SqlParameter("@City", objInfo.City),
            new SqlParameter("@Region", objInfo.Region),
            new SqlParameter("@PostalCode", objInfo.PostalCode),
            new SqlParameter("@Country", objInfo.Country),
            new SqlParameter("@Phone", objInfo.Phone),
            new SqlParameter("@EmailAddress", objInfo.EmailAddress)
            ));
    }

    public static void UpdateContact(ContactInfo objInfo)
    {
        SqlHelper.ExecuteNonQuery(ConnectionString, NamePrefix + "UpdateContact",
            new SqlParameter("@ContactId", objInfo.ContactId),
            new SqlParameter("@FirstName", objInfo.FirstName),
            new SqlParameter("@LastName", objInfo.LastName),
            new SqlParameter("@Address", objInfo.Address),
            new SqlParameter("@City", objInfo.City),
            new SqlParameter("@Region", objInfo.Region),
            new SqlParameter("@PostalCode", objInfo.PostalCode),
            new SqlParameter("@Country", objInfo.Country),
            new SqlParameter("@Phone", objInfo.Phone),
            new SqlParameter("@EmailAddress", objInfo.EmailAddress)
            );
    }

    public static void DeleteContact(int ContactId)
    {
        SqlHelper.ExecuteNonQuery(ConnectionString, NamePrefix + "DeleteContact",
            new SqlParameter("@ContactId", ContactId)
            );
    }

    #endregion

}

The ContactController.cs is as shown below. The web application will use this to interface with the SQL Database.

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Reflection;
using System.Web;

/// <summary>
/// Summary description for ContactController
/// </summary>
public class ContactController
{
    #region Constructors

    public ContactController()
    {
    }

    #endregion

    #region Contact Public Methods

    /// -----------------------------------------------------------------------------
    /// <summary>
    /// gets an object from the database
    /// </summary>
    /// <remarks>
    /// </remarks>
    /// <param name="ContactId">The Id of the Contact</param>
    /// <history>
    /// </history>
    /// -----------------------------------------------------------------------------
    public List<ContactInfo> GetAllContacts()
    {
        return DataProvider.GetAllContacts();
    }

    public ContactInfo GetContact(int ContactId)
    {
        return DataProvider.GetContact(ContactId);
    }

    public int AddContact(ContactInfo objInfo)
    {
        return DataProvider.AddContact(objInfo);
    }

    public void UpdateContact(ContactInfo objInfo)
    {
        DataProvider.UpdateContact(objInfo);
    }

    public void DeleteContact(int ContactId)
    {
        DataProvider.DeleteContact(ContactId);
    }

    #endregion
}

Using the Code

The Default.aspx will display the Editable Gridview using the code below. The gvContact_PreRender is required for the Gridview. The JavaScript is at the bottom to initialize the Gridview. When the OnRowCommand open modal dialog, the display is changed; after the modal closed, the Gridview will be refreshed.

<%@ Page Language="C#" AutoEventWireup="true" 

CodeFile="Default.aspx.cs" Inherits="_Default" %>

<!DOCTYPE html>

<html xmlns="<a href="http://www.w3.org/1999/xhtml">http://www.w3.org/1999/xhtml</a>">
<head runat="server">
    <title></title>

    <!-- Bootstrap -->
    <link href="bootstrap/css/bootstrap.min.css" rel="stylesheet" />

    <!-- Datatables-->
    <link href="bootstrap/vendors/datatables.net-bs4/css/dataTables.bootstrap4.min.css" 

     rel="stylesheet" />

</head>
<body>
    <form id="form1" runat="server">
        <asp:ScriptManager runat="server"></asp:ScriptManager>

        <div class="container">
            <div class="jumbotron text-center">
                <h1>My Contact</h1>
                <asp:Button ID="btnAdd" 

                runat="server" Text="Add New Record" 

                 CssClass="btn btn-info" OnClick="btnAdd_Click" />
            </div>

            <asp:UpdatePanel ID="upCrudGrid" runat="server">
                <ContentTemplate>
                    <asp:GridView ID="gvContact" runat="server" 

                    AutoGenerateColumns="false" DataKeyNames="ContactId"

                        OnPreRender="gvContact_PreRender"

                        OnRowCommand="gvContact_RowCommand"

                        CssClass="table table-striped">
                        <EmptyDataTemplate>
                            <asp:Image ID="Image0" 

                            ImageUrl="~/Images/yellow-warning.gif" 

                            AlternateText="No Image" runat="server" 

                            Visible="false" />No Data Found.
                        </EmptyDataTemplate>
                        <Columns>
                            <asp:ButtonField CommandName="detail" 

                            ControlStyle-CssClass="btn btn-info" 

                            ButtonType="Button" Text="Detail" 

                            HeaderText="" ItemStyle-CssClass="text-center">
                                <ControlStyle CssClass="btn btn-info"></ControlStyle>
                            </asp:ButtonField>
                            <asp:ButtonField CommandName="editRecord" 

                            ControlStyle-CssClass="btn btn-info" 

                            ButtonType="Button" Text="Edit" 

                            HeaderText="" ItemStyle-CssClass="text-center">
                                <ControlStyle CssClass="btn btn-info"></ControlStyle>
                            </asp:ButtonField>
                            <asp:ButtonField CommandName="deleteRecord" 

                            ControlStyle-CssClass="btn btn-info" 

                            ButtonType="Button" Text="Delete" 

                            HeaderText="" ItemStyle-CssClass="text-center">
                                <ControlStyle CssClass="btn btn-info"></ControlStyle>
                            </asp:ButtonField>
                            <asp:BoundField DataField="FullName" 

                            SortExpression="FullName" HeaderText="Name" />
                            <asp:BoundField DataField="FullAddress" 

                            SortExpression="FullAddress" HeaderText="Address" />
                            <asp:BoundField DataField="Phone" 

                            SortExpression="Phone" HeaderText="Phone" />
                            <asp:BoundField DataField="EmailAddress" 

                            SortExpression="EmailAddress" HeaderText="Email Address" />
                        </Columns>
                    </asp:GridView>
                </ContentTemplate>
            </asp:UpdatePanel>

            <!-- Modal -->
            <div id="detailModal" class="modal hide fade" 

            tabindex="-1" role="dialog" 

            aria-labelledby="myModalLabel" aria-hidden="true">
                <div class="modal-dialog modal-xl" role="document">
                    <div class="modal-content">
                        <div class="modal-header">
                            <h3 id="myModalLabel">Details</h3>
                            <button type="button" class="close" 

                            data-dismiss="modal" aria-label="Close">
                                <span aria-hidden="true">&times;</span>
                            </button>
                        </div>
                        <div class="modal-body">
                            <asp:UpdatePanel ID="UpdatePanel2" runat="server">
                                <ContentTemplate>
                                    <asp:DetailsView ID="DetailsView1" 

                                    runat="server" CssClass="table table-bordered table-hover"

                                        BackColor="White" ForeColor="Black"

                                        FieldHeaderStyle-Wrap="false"

                                        FieldHeaderStyle-Font-Bold="true"

                                        FieldHeaderStyle-BackColor="LavenderBlush"

                                        FieldHeaderStyle-ForeColor="Black" 

                                        BorderStyle="Groove" AutoGenerateRows="False">
                                        <Fields>
                                            <asp:BoundField DataField="FullName" 

                                            HeaderText="Name" />
                                            <asp:BoundField DataField="DisplayAddress" 

                                            HeaderText="Address" HtmlEncode="false" />
                                            <asp:BoundField DataField="Phone" 

                                            HeaderText="Phone" />
                                            <asp:BoundField DataField="EmailAddress" 

                                            HeaderText="EmailAddress" />
                                            <asp:BoundField DataField="CreatedDate" 

                                            HeaderText="Created Date" />
                                            <asp:TemplateField HeaderText="Updated Date">
                                                <ItemTemplate>
                                                    <%# (DateTime)Eval("UpdatedDate") == 
                                                    (DateTime.MinValue) ? "" : string.Format
                                                    ("{0:dd/MM/yyyy hh:mm:ss tt}", 
                                                    (DateTime)Eval("UpdatedDate")) %>
                                                </ItemTemplate>
                                            </asp:TemplateField>
                                        </Fields>
                                    </asp:DetailsView>
                                </ContentTemplate>

                                <Triggers>
                                    <asp:AsyncPostBackTrigger ControlID="gvContact" 

                                    EventName="RowCommand" />
                                    <asp:AsyncPostBackTrigger ControlID="btnAdd" 

                                    EventName="Click" />
                                </Triggers>
                            </asp:UpdatePanel>
                            <div class="modal-footer">
                                <button class="btn btn-info" 

                                data-dismiss="modal" 

                                aria-hidden="true">Close</button>
                            </div>
                        </div>
                    </div>
                    <!-- /.modal-content -->
                </div>
                <!-- /.modal-dialog -->
            </div>
            <!-- /.modal -->

            <!-- Modal -->
            <div id="editModal" class="modal hide fade" 

            tabindex="-1" role="dialog" 

            aria-labelledby="editModalLabel" aria-hidden="true">
                <div class="modal-dialog modal-xl" role="document">
                    <div class="modal-content">
                        <div class="modal-header">
                            <h3 id="editModalLabel">Edit Record</h3>
                            <button type="button" class="close" 

                            data-dismiss="modal" aria-label="Close">
                                <span aria-hidden="true">&times;</span>
                            </button>
                        </div>
                        <asp:UpdatePanel ID="upEdit" runat="server">
                            <ContentTemplate>
                                <div class="modal-body">
                                    <asp:HiddenField ID="HfUpdateID" 

                                    runat="server" />
                                    <table class="table">
                                        <tr>
                                            <td>First Name : </td>
                                            <td>
                                                <asp:TextBox ID="txtFirstNameUpdate" 

                                                runat="server" Width="100%" />
                                                <asp:RequiredFieldValidator 

                                                    ID="valFirstNameUpdate" 

                                                ControlToValidate="txtFirstNameUpdate" 

                                                EnableClientScript="False" Display="Dynamic"

                                                    Text="<br />* First Name is required" 

                                                    Font-Bold="true" ForeColor="Red" 

                                                    runat="server"

                                                    ValidationGroup="ValidationGroupUpdate" />
                                            </td>
                                            <td>
                                        </tr>
                                        <tr>
                                            <td>Last Name :</td>
                                            <td>
                                                <asp:TextBox ID="txtLastNameUpdate" 

                                                runat="server" Width="100%" />
                                                <asp:RequiredFieldValidator _

                                                     ID="valLastNameUpdate" 

                                                ControlToValidate="txtLastNameUpdate" 

                                                EnableClientScript="False" Display="Dynamic"

                                                    Text="<br />* Last Name is required" 

                                                    Font-Bold="true" ForeColor="Red" _

                                                    runat="server"

                                                    ValidationGroup="ValidationGroupUpdate" />
                                            </td>
                                        </tr>
                                        <tr>
                                            <td>Address :</td>
                                            <td>
                                                <asp:TextBox ID="txtAddressUpdate" 

                                                runat="server" Width="100%" /></td>
                                        </tr>
                                        <tr>
                                            <td>City :</td>
                                            <td>
                                                <asp:TextBox ID="txtCityUpdate" 

                                                runat="server" Width="100%" /></td>
                                        </tr>
                                        <tr>
                                            <td>Region :</td>
                                            <td>
                                                <asp:TextBox ID="txtRegionUpdate" 

                                                runat="server" Width="100%" /></td>
                                        </tr>
                                        <tr>
                                            <td>Postal Code :</td>
                                            <td>
                                                <asp:TextBox ID="txtPostalCodeUpdate" 

                                                runat="server" Width="100%" /></td>
                                        </tr>
                                        <tr>
                                            <td>Country :</td>
                                            <td>
                                                <asp:TextBox ID="txtCountryUpdate" 

                                                runat="server" Width="100%" /></td>
                                        </tr>
                                        <tr>
                                            <td>Phone :</td>
                                            <td>
                                                <asp:TextBox ID="txtPhoneUpdate" 

                                                runat="server" Width="100%" /></td>
                                        </tr>
                                        <tr>
                                            <td>Email Address :</td>
                                            <td>
                                                <asp:TextBox ID="txtEmailAddressUpdate" 

                                                runat="server" Width="100%" /></td>
                                        </tr>
                                    </table>
                                </div>
                                <div class="modal-footer">
                                    <asp:Label ID="lblResult" 

                                    Visible="false" runat="server"></asp:Label>
                                    <asp:Button ID="btnSave" 

                                    runat="server" Text="Update" 

                                    CssClass="btn btn-info" 

                                    ValidationGroup="ValidationGroupUpdate" 

                                           OnClick="btnUpdate_Click" />
                                    <button class="btn btn-info" 

                                    data-dismiss="modal" 

                                    aria-hidden="true">Close</button>

                                </div>
                            </ContentTemplate>
                            <Triggers>
                                <asp:AsyncPostBackTrigger ControlID="gvContact" 

                                EventName="RowCommand" />
                                <asp:AsyncPostBackTrigger ControlID="btnSave" 

                                EventName="Click" />
                            </Triggers>
                        </asp:UpdatePanel>
                    </div>
                    <!-- /.modal-content -->
                </div>
                <!-- /.modal-dialog -->
            </div>
            <!-- /.modal -->

            <asp:Label ID="lblMessage" runat="server" />

            <!-- Modal -->
            <div id="addModal" class="modal hide fade" 

            tabindex="-1" role="dialog" 

            aria-labelledby="addModalLabel" aria-hidden="true">
                <div class="modal-dialog" role="document">
                    <div class="modal-content">
                        <div class="modal-header">
                            <h3 id="addModalLabel">Add New Record</h3>
                            <button type="button" class="close" 

                            data-dismiss="modal" aria-label="Close">
                                <span aria-hidden="true">&times;</span>
                            </button>
                        </div>
                        <asp:UpdatePanel ID="upAdd" runat="server">
                            <ContentTemplate>
                                <div class="modal-body">
                                    <table class="table table-bordered table-hover">
                                        <tr>
                                            <td>First Name : </td>
                                            <td>
                                                <asp:TextBox ID="txtFirstNameAdd" 

                                                runat="server" Width="100%" />
                                                <asp:RequiredFieldValidator 

                                                ID="valFirstNameAdd" 

                                                ControlToValidate="txtFirstNameAdd" 

                                                EnableClientScript="False" Display="Dynamic"

                                                    Text="<br />* First Name is required" 

                                                    Font-Bold="true" ForeColor="Red" 

                                                    runat="server"

                                                    ValidationGroup="ValidationGroupAdd" />
                                             </td>
                                        </tr>
                                        <tr>
                                            <td>Last Name :</td>
                                            <td>
                                                <asp:TextBox ID="txtLastNameAdd" 

                                                runat="server" Width="100%" />
                                                <asp:RequiredFieldValidator ID="valLastNameAdd" 

                                                ControlToValidate="txtLastNameAdd" 

                                                EnableClientScript="False" Display="Dynamic"

                                                    Text="<br />* Last Name is required" 

                                                    Font-Bold="true" ForeColor="Red" 

                                                    runat="server"

                                                    ValidationGroup="ValidationGroupAdd" />
                                            </td>
                                        </tr>
                                        <tr>
                                            <td>Address :</td>
                                            <td>
                                                <asp:TextBox ID="txtAddressAdd" 

                                                runat="server" Width="100%" /></td>
                                        </tr>
                                        <tr>
                                            <td>City :</td>
                                            <td>
                                                <asp:TextBox ID="txtCityAdd" 

                                                runat="server" Width="100%" /></td>
                                        </tr>
                                        <tr>
                                            <td>Region :</td>
                                            <td>
                                                <asp:TextBox ID="txtRegionAdd" 

                                                runat="server" Width="100%" /></td>
                                        </tr>
                                        <tr>
                                            <td>Postal Code :</td>
                                            <td>
                                                <asp:TextBox ID="txtPostalCodeAdd" 

                                                runat="server" Width="100%" /></td>
                                        </tr>
                                        <tr>
                                            <td>Country :</td>
                                            <td>
                                                <asp:TextBox ID="txtCountryAdd" 

                                                runat="server" Width="100%" /></td>
                                        </tr>
                                        <tr>
                                            <td>Phone :</td>
                                            <td>
                                                <asp:TextBox ID="txtPhoneAdd" 

                                                runat="server" Width="100%" /></td>
                                        </tr>
                                        <tr>
                                            <td>Email Address :</td>
                                            <td>
                                                <asp:TextBox ID="txtEmailAddressAdd" 

                                                runat="server" Width="100%" /></td>
                                        </tr>
                                    </table>
                                </div>
                                <div class="modal-footer">
                                    <asp:Button ID="btnAddRecord" runat="server" 

                                    Text="Add" CssClass="btn btn-info" 

                                    ValidationGroup="ValidationGroupAdd" 

                                    OnClick="btnAddRecord_Click" />
                                    <button class="btn btn-info" 

                                    data-dismiss="modal" 

                                    aria-hidden="true">Close</button>

                                </div>
                            </ContentTemplate>
                            <Triggers>
                                <asp:AsyncPostBackTrigger ControlID="btnAddRecord" 

                                EventName="Click" />
                            </Triggers>
                        </asp:UpdatePanel>
                    </div>
                    <!-- /.modal-content -->
                </div>
                <!-- /.modal-dialog -->
            </div>
            <!-- /.modal -->

            <!-- Modal -->
            <div id="deleteModal" class="modal hide fade" 

            tabindex="-1" role="dialog" 

            aria-labelledby="delModalLabel" aria-hidden="true">
                <div class="modal-dialog" role="document">
                    <div class="modal-content">
                        <div class="modal-header">
                            <h3 id="delModalLabel">Delete Record</h3>
                            <button type="button" class="close" 

                            data-dismiss="modal" aria-label="Close">
                                <span aria-hidden="true">&times;</span>
                            </button>
                        </div>
                        <asp:UpdatePanel ID="upDel" runat="server">
                            <ContentTemplate>
                                <div class="modal-body">
                                    Are you sure you want to delete the record
                                    <asp:Label ID="lblFirstNameDelete" 

                                    runat="server"></asp:Label>
                                    ?
                                    <asp:HiddenField ID="HfDeleteID" 

                                    runat="server" />
                                </div>

                                <div class="modal-footer">
                                    <asp:Button ID="btnDelete" 

                                    runat="server" Text="Delete" 

                                    CssClass="btn btn-info" OnClick="btnDelete_Click" />
                                    <button class="btn btn-info" 

                                    data-dismiss="modal" 

                                    aria-hidden="true">Cancel</button>
                                </div>
                            </ContentTemplate>
                            <Triggers>
                                <asp:AsyncPostBackTrigger ControlID="btnDelete" 

                                EventName="Click" />
                            </Triggers>
                        </asp:UpdatePanel>
                    </div>
                    <!-- /.modal-content -->
                </div>
                <!-- /.modal-dialog -->
            </div>
            <!-- /.modal -->
        </div>

    </form>

    <!-- jQuery and Bootstrap JS files -->
    <script src="bootstrap/js/jquery-3.3.1.min.js"></script>
    <script src="bootstrap/js/popper.min.js"></script>
    <script src="bootstrap/js/bootstrap.min.js"></script>

    <!-- Datatables-->
    <script src="bootstrap/vendors/datatables.net/js/jquery.dataTables.min.js"></script>
    <script src="bootstrap/vendors/datatables.net-bs4/js/dataTables.bootstrap4.min.js">
    </script>

    <!-- pace -->
    <script type="text/javascript">
        $(document).ready(function () {
            $('#<%= gvContact.ClientID %>').dataTable({
                "aLengthMenu": [[5, 10, 50, -1], [5, 10, 50, "All"]],
                "iDisplayLength": 5,
                "order": [[3, "asc"]],
                stateSave: true,
                stateSaveCallback: function (settings, data) {
                    localStorage.setItem
                        ('DataTables_' + settings.sInstance, JSON.stringify(data));
                },
                stateLoadCallback: function (settings) {
                    return JSON.parse
                    (localStorage.getItem('DataTables_' + settings.sInstance));
                }
            });
        });

        //The scripts below to restore the page changed by command
        $('#detailModal').on('hidden.bs.modal', function () {
            location.reload();
        })

        $('#editModal').on('hidden.bs.modal', function () {
            location.reload();
        })

        $('#addModal').on('hidden.bs.modal', function () {
            location.reload();
        })
        $('#deleteModal').on('hidden.bs.modal', function () {
            location.reload();
        })
    </script>

</body>

</html>

The Default.aspx.cs is shown below. After submitting the command, the Alert dialog will be displayed, the Gridview will be refreshed by DataLoad(), and Bootstrap Gridview will be refreshed by JavaScript location.reload().

using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

/// -----------------------------------------------------------------------------
/// <summary>
/// The initial will display the items in gridview
/// Typically your view control would be used to display content or 
/// functionality in your module.
/// View may be the only control you have in your project depending on the 
/// complexity of your module
/// </summary>
/// -----------------------------------------------------------------------------
public partial class _Default : System.Web.UI.Page
{
    #region "Private Variables"

    private ContactController objCtrl = new ContactController();
    private List<ContactInfo> objInfos = new List<ContactInfo>();
    private ContactInfo objInfo = new ContactInfo();
    private int ContactId = 0;

    #endregion

    /// -----------------------------------------------------------------------------
    /// <summary>
    /// Page_Load runs when this program start
    /// </summary>
    /// <remarks>
    /// </remarks>
    /// <history>
    /// </history>
    /// -----------------------------------------------------------------------------
    protected void Page_Load(object sender, EventArgs e)
    {
        DataLoad();
    }

    /// -----------------------------------------------------------------------------
    /// <summary>
    /// DataLoad will populate the gridview
    /// </summary>
    /// <remarks>
    /// </remarks>
    /// <history>
    /// </history>
    /// -----------------------------------------------------------------------------
    public void DataLoad()
    {
        lblMessage.Text = string.Empty;
        try
        {
            objInfos = objCtrl.GetAllContacts();
            gvContact.DataSource = objInfos;
            gvContact.DataBind();
        }
        catch (Exception ex)
        {
            lblMessage.Text = ex.Message;
        }
    }

    /// -----------------------------------------------------------------------------
    /// <summary>
    /// gvContact_PreRender prepares gridview in bootstrap
    /// </summary>
    /// <remarks>
    /// </remarks>
    /// <history>
    /// </history>
    /// -----------------------------------------------------------------------------
    protected void gvContact_PreRender(object sender, EventArgs e)
    {
        GridView gv = (GridView)sender;

        if ((gv.ShowHeader == true && gv.Rows.Count > 0)
            || (gv.ShowHeaderWhenEmpty == true))
        {
            //Force GridView to use <thead> instead of <tbody>
            gv.HeaderRow.TableSection = TableRowSection.TableHeader;
        }
        if (gv.ShowFooter == true && gv.Rows.Count > 0)
        {
            //Force GridView to use <tfoot> instead of <tbody>
            gv.FooterRow.TableSection = TableRowSection.TableFooter;
        }
    }

    /// -----------------------------------------------------------------------------
    /// <summary>
    /// gvContact_RowCommand will open specific modal dialog when the 
    /// button command in gridview is clicked
    /// </summary>
    /// <remarks>
    /// </remarks>
    /// <history>
    /// </history>
    /// -----------------------------------------------------------------------------
    protected void gvContact_RowCommand(object sender, GridViewCommandEventArgs e)
    {
        // Find the row index
        int index = Convert.ToInt32(e.CommandArgument);

        // Get the ContactId and object class
        int ContactId = Convert.ToInt32(gvContact.DataKeys[index].Value.ToString());
        var objInfo = objInfos.Where(i => i.ContactId == ContactId).First();

        if (e.CommandName.Equals("detail"))
        {
            var detailInfos = objInfos.Where(i => i.ContactId == ContactId);
            DetailsView1.DataSource = detailInfos;
            DetailsView1.DataBind();
            System.Text.StringBuilder sb = new System.Text.StringBuilder();
            sb.Append(@"<script type='text/javascript'>");
            sb.Append("$('#detailModal').modal('show');");
            sb.Append(@"</script>");
            ScriptManager.RegisterClientScriptBlock
               (this, this.GetType(), "DetailModalScript", sb.ToString(), false);
        }
        if (e.CommandName.Equals("editRecord"))
        {
            HfUpdateID.Value = objInfo.ContactId.ToString();
            txtFirstNameUpdate.Text = objInfo.FirstName;
            txtLastNameUpdate.Text = objInfo.LastName;
            txtAddressUpdate.Text = objInfo.Address;
            txtCityUpdate.Text = objInfo.City;
            txtRegionUpdate.Text = objInfo.Region;
            txtPostalCodeUpdate.Text = objInfo.PostalCode;
            txtCountryUpdate.Text = objInfo.Country;
            txtPhoneUpdate.Text = objInfo.Phone;
            txtEmailAddressUpdate.Text = objInfo.EmailAddress;
            lblResult.Visible = false;
            System.Text.StringBuilder sb = new System.Text.StringBuilder();
            sb.Append(@"<script type='text/javascript'>");
            sb.Append("$('#editModal').modal('show');");
            sb.Append(@"</script>");
            ScriptManager.RegisterClientScriptBlock
                (this, this.GetType(), "EditModalScript", sb.ToString(), false);
        }
        if (e.CommandName.Equals("deleteRecord"))
        {
            HfDeleteID.Value = objInfo.ContactId.ToString();
            lblFirstNameDelete.Text = objInfo.FirstName;
            System.Text.StringBuilder sb = new System.Text.StringBuilder();
            sb.Append(@"<script type='text/javascript'>");
            sb.Append("$('#deleteModal').modal('show');");
            sb.Append(@"</script>");
            ScriptManager.RegisterClientScriptBlock
                 (this, this.GetType(), "DeleteModalScript", sb.ToString(), false);
        }
    }

    #region "Optional Command Interfaces"

    /// -----------------------------------------------------------------------------
    /// <summary>
    /// btnAdd_Click will open add new record modal dialog when the 
    /// add new record button is clicked
    /// </summary>
    /// <remarks>
    /// </remarks>
    /// <history>
    /// </history>
    /// -----------------------------------------------------------------------------
    protected void btnAdd_Click(object sender, EventArgs e)
    {
        System.Text.StringBuilder sb = new System.Text.StringBuilder();
        sb.Append(@"<script type='text/javascript'>");
        sb.Append("$('#addModal').modal('show');");
        sb.Append(@"</script>");
        ScriptManager.RegisterClientScriptBlock(this, this.GetType(), 
                   "AddShowModalScript", sb.ToString(), false);
    }

    /// -----------------------------------------------------------------------------
    /// <summary>
    /// btnUpdate_Click will update record from modal dialog when the 
    /// update record button is clicked
    /// </summary>
    /// <remarks>
    /// </remarks>
    /// <history>
    /// </history>
    /// -----------------------------------------------------------------------------
    protected void btnUpdate_Click(object sender, EventArgs e)
    {
        if (Page.IsValid)
        {
            lblMessage.Text = string.Empty;
            try
            {
                objInfo = new ContactInfo();
                objInfo.ContactId = Convert.ToInt32(HfUpdateID.Value);
                objInfo.FirstName = txtFirstNameUpdate.Text;
                objInfo.LastName = txtLastNameUpdate.Text;
                objInfo.Address = txtAddressUpdate.Text;
                objInfo.City = txtCityUpdate.Text;
                objInfo.Region = txtRegionUpdate.Text;
                objInfo.PostalCode = txtPostalCodeUpdate.Text;
                objInfo.Country = txtCountryUpdate.Text;
                objInfo.Phone = txtPhoneUpdate.Text;
                objInfo.EmailAddress = txtEmailAddressUpdate.Text;
                objCtrl.UpdateContact(objInfo);
            }
            catch (Exception ex)
            {
                lblMessage.Text = ex.Message;
            }

            DataLoad();

            // remove the alert() below to skip the confirm  message
            System.Text.StringBuilder sb = new System.Text.StringBuilder();
            sb.Append(@"<script type='text/javascript'>");
            sb.Append("alert('Records Updated Successfully');");
            sb.Append("$('#editModal').modal('hide');");
            sb.Append(@"</script>");
            ScriptManager.RegisterClientScriptBlock
                 (this, this.GetType(), "EditHideModalScript", sb.ToString(), false);
        }
    }

    /// -----------------------------------------------------------------------------
    /// <summary>
    /// btnDelete_Click will delete record from modal dialog 
    /// when the delete record button is clicked
    /// </summary>
    /// <remarks>
    /// </remarks>
    /// <history>
    /// </history>
    /// -----------------------------------------------------------------------------
    protected void btnDelete_Click(object sender, EventArgs e)
    {
        lblMessage.Text = string.Empty;
        try
        {
            ContactId = Convert.ToInt32(HfDeleteID.Value);
            objCtrl.DeleteContact(ContactId);
        }
        catch (Exception ex)
        {
            lblMessage.Text = ex.Message;
        }

        DataLoad();

        // remove the alert() below to skip the confirm  message
        System.Text.StringBuilder sb = new System.Text.StringBuilder();
        sb.Append(@"<script type='text/javascript'>");
        sb.Append("alert('Record deleted Successfully');");
        sb.Append("$('#deleteModal').modal('hide');");
        sb.Append(@"</script>");

        ScriptManager.RegisterClientScriptBlock(this, this.GetType(), 
                          "delHideModalScript", sb.ToString(), false);
    }

    /// -----------------------------------------------------------------------------
    /// <summary>
    /// btnAddRecord_Click will add new record from modal dialog 
    /// when the add record button is clicked
    /// </summary>
    /// <remarks>
    /// </remarks>
    /// <history>
    /// </history>
    /// -----------------------------------------------------------------------------
    protected void btnAddRecord_Click(object sender, EventArgs e)
    {
        if (Page.IsValid)
        {
            lblMessage.Text = string.Empty;
            try
            {
                ContactController objCtrl = new ContactController();
                ContactInfo objInfo = new ContactInfo();
                objInfo.FirstName = txtFirstNameAdd.Text;
                objInfo.LastName = txtLastNameAdd.Text;
                objInfo.Address = txtAddressAdd.Text;
                objInfo.City = txtCityAdd.Text;
                objInfo.Region = txtRegionAdd.Text;
                objInfo.PostalCode = txtPostalCodeAdd.Text;
                objInfo.Country = txtCountryAdd.Text;
                objInfo.Phone = txtPhoneAdd.Text;
                objInfo.EmailAddress = txtEmailAddressAdd.Text;
                objCtrl.AddContact(objInfo);
            }
            catch (Exception ex)
            {
                lblMessage.Text = ex.Message;
            }

            DataLoad();

            // remove the alert() below to skip the confirm  message
            System.Text.StringBuilder sb = new System.Text.StringBuilder();
            sb.Append(@"<script type='text/javascript'>");
            sb.Append("alert('Record Added Successfully');");
            sb.Append("$('#addModal').modal('hide');");
            sb.Append(@"</script>");
            ScriptManager.RegisterClientScriptBlock(this, this.GetType(), 
                               "AddHideModalScript", sb.ToString(), false);
        }
    }

    #endregion
}

This is the Home Page.

The Add New Record:

The Detail Page:

The Edit Page:

The Delete Page:

Points of Interest

Did you notice we did not create OnPageIndexChanging, OnSorting, SaveViewState, etc. for the Gridview? Everything is done by Bootstrap. You can browse the sub folder http://localhost/MyGridview/bootstrap/index.html to see what the Sufee can do. You can invest time to learn how to use the bootstrap CSS and JS files for your future project. Happy programming!

History

This is my second article, and I hope you like to save time while creating an ASP.NET Gridview by using bootstrap in ASP.NET.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here