The ASP.NET WebGrid (ASP.NET MVC) (25 min)
Tools required: (minimum)
-
Microsoft SQL Server express
We
usually have to build web applications that need to present large chunks of
data to the user in a tabular fashion in a way that offers the end user a
pleasant experience while interacting with our application. Although there are
open source and licensed products, I’d like to present in this post a data grid
that takes very little effort to do the job: WebGrid.
I
am going guide you through the process of creating a web page with a grid to
present a quiet short chunk of data in a decent way while taking care of
pagination, ordering and filtering.
1) We will
start by creating a new ASP.NET MVC4 Web Application: WebGridDemo.
2) From Installed Templates select Visual C# > ASP.NET
MVC4 Web Application > Click OK and then select template: Basic
(An basic ASP.NET MVC 4 project)
Please don’t change the view engine
unless you’d like to have messy views. Create a Unit Test project? Up to you.
3) Give it a moment… done. We can now create our
default controller: HomeController. Right click on Controllers folder, select Add
>>> Controller… option.
Template: Empty MVC controller
4) We’ll do now some set up work. To make it a bit
realistic we will create a simple database with a table from where we are going
to pull the data for our grid.
Open Microsoft SQL Server Management
Studio and execute the following script. We are creating a Database and a table
with some data to play with in our grid.
USE [master]
GO
CREATE DATABASE
[TestDb] ON
PRIMARY
( NAME = N'TestDb', FILENAME = N'C:\MyProjects\Databases\TestDb.mdf' , SIZE = 2048KB , MAXSIZE = UNLIMITED, FILEGROWTH
= 1024KB )
LOG ON
( NAME = N'TestDb_log', FILENAME = N'C:\MyProjects\Databases\TestDb_log.ldf' , SIZE = 1024KB , MAXSIZE = 2048GB , FILEGROWTH = 10%)
GO
USE [TestDb]
GO
CREATE TABLE
[dbo].[Persons](
[PersonId] [int] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](100) NOT NULL,
[Email] [nvarchar](100) NOT NULL,
[Phone] [nvarchar](50) NOT NULL,
[BirthDate]
[datetime] NOT NULL,
[HasFacebook]
[bit] NOT NULL,
CONSTRAINT [PK_Persons] PRIMARY
KEY CLUSTERED
(
[PersonId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS
= ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
INSERT INTO
Persons( Name,
Email, Phone,
BirthDate, HasFacebook)
SELECT 'Chilly
Willy', 'Chilly@email.com', '905-234-1234', CAST( '01/28/2000' AS DATETIME), 1
UNION SELECT
'William Hanna',
'Hanna@email.com',
'905-234-0001', CAST( '01/01/1990' AS DATETIME), 1
UNION SELECT
'Fred Flintstone',
'Fred@email.com',
'905-234-0002', CAST( '01/01/1990' AS DATETIME), 1
UNION SELECT
'Wilma Flintstone',
'Wilma@Flintstone.com',
'905-234-0002', CAST( '01/01/1990' AS DATETIME), 1
UNION SELECT
'Mazinger Z', 'ZMazinger@email.com',
'905-234-1235', CAST( '01/28/1988' AS DATETIME), 0
UNION SELECT
'Inspector Clouseau',
'Clouseau@email.com',
'905-234-0001', CAST( '01/01/1990' AS DATETIME), 0
UNION SELECT
'Mario Test', 'Mario@email.com', '905-234-0002', CAST( '01/01/1990' AS DATETIME), 1
UNION SELECT
'Maria Test', 'Maria@Flintstone.com',
'905-234-0002', CAST( '01/01/1990' AS DATETIME), 1
UNION SELECT
'Tom Cat', 'Tom@email.com', '905-234-0002', CAST( '01/01/1990' AS DATETIME), 1
UNION SELECT
'Jerry Mouse', 'Jerry@Flintstone.com',
'905-234-0002', CAST( '01/01/1990' AS DATETIME), 1
UNION SELECT
'Yogi Bear', 'Yogi@Flintstone.com',
'905-234-0002', CAST( '01/01/1990' AS DATETIME), 1
UNION SELECT
'Quan Chi', 'Yogi@Flintstone.com',
'905-234-0002', CAST( '01/01/1990' AS DATETIME), 0
UNION SELECT
'Chilly Willy1',
'Chilly1@email.com',
'905-234-1234', CAST( '01/28/2000' AS DATETIME), 1
UNION SELECT
'William Hanna1',
'Hanna1@email.com',
'905-234-0001', CAST( '01/01/1990' AS DATETIME), 1
UNION SELECT
'Fred Flintstone1',
'Fred1@email.com',
'905-234-0002', CAST( '01/01/1990' AS DATETIME), 1
UNION SELECT
'Wilma Flintstone1',
'Wilma1@Flintstone.com',
'905-234-0002', CAST( '01/01/1990' AS DATETIME), 1
UNION SELECT
'Mazinger Z1', 'ZMazinger1@email.com',
'905-234-1235', CAST( '01/28/1988' AS DATETIME), 0
UNION SELECT
'Inspector Clouseau1',
'Clouseau1@email.com',
'905-234-0001', CAST( '01/01/1990' AS DATETIME), 0
UNION SELECT
'Mario Test1', 'Mario1@email.com', '905-234-0002', CAST( '01/01/1990' AS DATETIME), 1
UNION SELECT
'Maria Test1', 'Maria1@Flintstone.com',
'905-234-0002', CAST( '01/01/1990' AS DATETIME), 1
UNION SELECT
'Tom Cat1', 'Tom1@email.com', '905-234-0002', CAST( '01/01/1990' AS DATETIME), 1
UNION SELECT
'Jerry Mouse1', 'Jerry1@Flintstone.com',
'905-234-0002', CAST( '01/01/1990' AS DATETIME), 1
UNION SELECT
'Yogi Bear1', 'Yogi1@Flintstone.com',
'905-234-0002', CAST( '01/01/1990' AS DATETIME), 1
UNION SELECT
'Quan Chi1', 'Quan1@Flintstone.com',
'905-234-0002', CAST( '01/01/1990' AS DATETIME), 0
UNION SELECT
'Chilly Willy2',
'Chilly1@email.com',
'905-234-1234', CAST( '01/28/2000' AS DATETIME), 1
UNION SELECT
'William Hanna2',
'Hanna1@email.com',
'905-234-0001', CAST( '01/01/1990' AS DATETIME), 1
UNION SELECT
'Fred Flintstone2',
'Fred1@email.com',
'905-234-0002', CAST( '01/01/1990' AS DATETIME), 1
UNION SELECT
'Wilma Flintstone2',
'Wilma1@Flintstone.com',
'905-234-0002', CAST( '01/01/1990' AS DATETIME), 1
UNION SELECT
'Mazinger Z2', 'ZMazinger1@email.com',
'905-234-1235', CAST( '01/28/1988' AS DATETIME), 0
UNION SELECT
'Inspector Clouseau2',
'Clouseau1@email.com',
'905-234-0001', CAST( '01/01/1990' AS DATETIME), 0
UNION SELECT
'Mario Test2', 'Mario1@email.com', '905-234-0002', CAST( '01/01/1990' AS DATETIME), 1
UNION SELECT
'Maria Test2', 'Maria1@Flintstone.com',
'905-234-0002', CAST( '01/01/1990' AS DATETIME), 1
UNION SELECT
'Tom Cat2', 'Tom1@email.com', '905-234-0002', CAST( '01/01/1990' AS DATETIME), 1
UNION SELECT
'Jerry Mouse2', 'Jerry1@Flintstone.com',
'905-234-0002', CAST( '01/01/1990' AS DATETIME), 1
UNION SELECT
'Yogi Bear2', 'Yogi1@Flintstone.com',
'905-234-0002', CAST( '01/01/1990' AS DATETIME), 1
UNION SELECT
'Quan Chi2', 'Quan1@Flintstone.com',
'905-234-0002', CAST( '01/01/1990' AS DATETIME), 0
5) To be able to use WebGrid we need to add a
reference to our project. Right click on References and select Add Reference…
6) You might also need to open the Web.Config and add
the assembly highlighted in the following picture.
7) Now lets add The Entity Framework, Right click on
the project, Select add >>>
New Item
Select Data >>> ADO.NET
Entity Data Model >>> Click Add
button
Generate
from Database >>> Add a new Connection to TestDb.
>>> Click Next >>>
Include Tables in your model
>> Click Finish Button
8) We are going to add our model to transport our
list of persons to the view that will show the person’s grid to the user. Right
click on the folder named Models and
select Class... >>> name: PersonModel.cs >>> Click Add Button.
9) Replace the current class in the PersonModel with
the following code:
namespace WebGridDemo.Models
{
public class PersonModel
{
public List<Person> Persons { get; set; }
public PagingModel Paging { get; set; }
}
public class PagingModel
{
public int Total { get; set; }
public int CurrentPage { get; set; }
public bool HasMorePages { get; set; }
}
}
10)We have a Controller and a
Model, now we need to create our View. Let’s open our HomeController and
replace the code of the only method in
our controller (named Index) with
the following code:
public ActionResult Index(int page=1, int pageSize=5)
{
var model = new PersonModel() { Paging = new PagingModel()};
var ef = new TestDbEntities();
model.Persons =
ef.Persons.OrderBy(p=>p.PersonId).Skip((page - 1) *
pageSize).Take(pageSize).ToList();
model.Paging.Total =
ef.Persons.Count();
model.Paging.CurrentPage = page;
model.Paging.HasMorePages = page *
pageSize < model.Paging.Total;
return View(model);
}
Note: Resolve errors. (Right click on the
red-highlighted errors and select resolve with the proper using statement)
11)Right click on the method you just added (the Index Action Method) and select Add View…
12) Replace the code generated for you in the view with the following:
Note: Take a look how easy the grid is set up and its
pagination.
@model
WebGridDemo.Models.PersonModel
@{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
var personsWebGrid = new WebGrid(Model.Persons);
}
@personsWebGrid.GetHtml(
htmlAttributes: new {@class="responsive"},
alternatingRowStyle: "alt",
columns:
personsWebGrid.Columns
(
personsWebGrid.Column("Person ID",
format: @<text>@Html.ActionLink((string)item.PersonId.ToString(), "Detail", new { PersonId = item.PersonId }, new { @class="tiny button" })</text>),
personsWebGrid.Column("Name", "Name"),
personsWebGrid.Column("Birth Date", "Birth Date",
format: @<text>@item.BirthDate.ToString("dd/MM/yyyy")</text>),
personsWebGrid.Column("Email", "Email"),
personsWebGrid.Column("Phone", "Appointment Type"),
personsWebGrid.Column("HasFacebook", "Has Facebook",
format: @<i class="foundicon-flag"></i>)
))
@*you can create either a helper to do this or a partial
view*@
<ul class="pagination">
@{
if (Model.Paging.CurrentPage > 1)
{
<li>
@Html.ActionLink("«", "Index", new { page = (Model.Paging.CurrentPage - 1) }, new { @class = "arrow unavailable" });
</li>
}
int position = Model.Paging.CurrentPage % 5;
int startPage = Model.Paging.CurrentPage -
(position==0?5:position)+1;
for( int p=startPage; p<startPage+5; p++)
{
if (p<= (Model.Paging.Total/5))
{
<li>
@Html.ActionLink(p.ToString(), "Index", new { page = p }, new { @class = (p ==
Model.Paging.CurrentPage ? "current" : "") });
</li>
}
}
if (Model.Paging.HasMorePages)
{
<li>
@Html.ActionLink("»", "Index", new { page = (Model.Paging.CurrentPage + 1) }, new { @class = "arrow" });
</li>
}
}
</ul>
13)Add a new Action Method in HomeController. The following code
represents the Action method that will be used to fetch a specific person
selected from the grid.
You will find that the grid has in the
first column a maybe “weird” button when clicked, fetches a person by its Id
and displays it a new page. The idea was to show that you can set up other
things in the grid (checkboxes, dropdowns, images, etc)
public ActionResult Detail(int personId)
{
var ef = new TestDbEntities();
var model = ef.Persons.Where(p => p.PersonId ==
personId).FirstOrDefault();
return View(model);
}
14)Add the View that is going
to be returned by the action method you just added.
15)Replace the code generated for you in the View with the following:
@model WebGridDemo.Person
@{
ViewBag.Title = "Detail";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Detail</h2>
<fieldset>
<legend>Person</legend>
<div class="display-label">
@Html.DisplayNameFor(model => model.Name)
</div>
<div class="display-field">
@Html.DisplayFor(model => model.Name)
</div>
<div class="display-label">
@Html.DisplayNameFor(model => model.Email)
</div>
<div class="display-field">
@Html.DisplayFor(model => model.Email)
</div>
<div class="display-label">
@Html.DisplayNameFor(model => model.Phone)
</div>
<div class="display-field">
@Html.DisplayFor(model => model.Phone)
</div>
<div class="display-label">
@Html.DisplayNameFor(model => model.BirthDate)
</div>
<div class="display-field">
@Html.DisplayFor(model => model.BirthDate)
</div>
<div class="display-label">
@Html.DisplayNameFor(model => model.HasFacebook)
</div>
<div class="display-field">
@Html.DisplayFor(model => model.HasFacebook)
</div>
</fieldset>
<p>
@Html.ActionLink("Back
to List", "Index", new { id=Model.PersonId }, new { @class = "small
button" })
</p>
16)I kind of became fan of foundation (from Zurb – the most advanced
responsive front-end framework in the world…). So we are going to download the package
to make use of some of its features: Click here to
download.
17) Extract (unzip) the files and copy the three
folders highlighted into your project as shown in the following image.
18)Now include those folders to your project. First click the icon “Show
All Files” and then right click on the folders that need to be added and select
include in project.
19)Go to the folder Views >>> Shared and open the file _layout.cshtml
and replace the current code with the following:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>@ViewBag.Title</title>
<!--
Set the viewport width to device width for mobile -->
<meta content="width=device-width" name="viewport">
<link rel="stylesheet" href="~/stylesheets/foundation.min.css"/>
<link rel="stylesheet" href="~/stylesheets/app.css"/>
<script type="text/javascript" src="~/javascripts/modernizr.foundation.js"></script>
<!--
IE Fix for HTML5 Tags -->
<!--[if
lt IE 9]>
<script
src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
</head>
<body>
<div class="container top-bar
home-border">
<div class="attached">
<div class="name">
<span><a href="#">the
WebGrid Demo </a>
</span>
</div>
</div>
</div>
<div class="row">
<div class="twelve
columns">
<h3>The WebGrid in MVC.</h3>
<hr>
</div>
</div>
<div class="row">
<div class="twelve
columns">
@RenderBody()
</div>
</div>
<script type="text/javascript" src="~/javascripts/jquery.js"></script>
<script type="text/javascript" src="~/javascripts/foundation.min.js"></script>
<!--
Initialize JS Plugins -->
<script type="text/javascript" src="~/javascripts/app.js"></script>
</body>
</html>
Considerations
The
trip in the train seemed to be shorter this time to include sorting and
filtering. I’ll continue with it soon.