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.
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 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
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 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'
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()
)
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
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;
public class ContactInfo
{
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;
public static class Helper
{
#region Helper
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;
}
}
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;
}
public static bool IsNullable(Type t)
{
return !t.IsValueType || _
(t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>));
}
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;
public abstract class DataProvider
{
public static string ConnectionString = "Data Source=localhost;
Initial Catalog=ChangeMe;User ID=sa;Password=ChangeMe";
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;
public class ContactController
{
#region Constructors
public ContactController()
{
}
#endregion
#region Contact Public Methods
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>
<link href="bootstrap/css/bootstrap.min.css" rel="stylesheet" />
<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>
<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">×</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>
</div>
</div>
<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">×</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>
</div>
</div>
<asp:Label ID="lblMessage" runat="server" />
<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">×</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>
</div>
</div>
<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">×</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>
</div>
</div>
</div>
</form>
<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>
<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>
<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));
}
});
});
$('#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;
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
protected void Page_Load(object sender, EventArgs e)
{
DataLoad();
}
public void DataLoad()
{
lblMessage.Text = string.Empty;
try
{
objInfos = objCtrl.GetAllContacts();
gvContact.DataSource = objInfos;
gvContact.DataBind();
}
catch (Exception ex)
{
lblMessage.Text = ex.Message;
}
}
protected void gvContact_PreRender(object sender, EventArgs e)
{
GridView gv = (GridView)sender;
if ((gv.ShowHeader == true && gv.Rows.Count > 0)
|| (gv.ShowHeaderWhenEmpty == true))
{
gv.HeaderRow.TableSection = TableRowSection.TableHeader;
}
if (gv.ShowFooter == true && gv.Rows.Count > 0)
{
gv.FooterRow.TableSection = TableRowSection.TableFooter;
}
}
protected void gvContact_RowCommand(object sender, GridViewCommandEventArgs e)
{
int index = Convert.ToInt32(e.CommandArgument);
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"
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);
}
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();
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);
}
}
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();
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);
}
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();
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.