۱۳۹۱/۰۲/۰۳

ASP.NET MVC #20


تهيه گزارشات تحت وب به كمك WebGrid

WebGrid از ASP.NET MVC 3.0 به صورت توكار به شكل يك Html Helper در دسترس مي‌باشد و هدف از آن ساده‌تر سازي تهيه گزارشات تحت وب است. البته اين گريد، تنها گريد مهياي مخصوص ASP.NET MVC نيست و پروژه MVC Contrib يا شركت Telerik نيز نمونه‌هاي ديگري را ارائه داده‌اند؛ اما از اين جهت كه اين Html Helper، بدون نياز به كتابخانه‌هاي جانبي در دسترس است، بررسي آن ضروري مي‌باشد.


صورت مساله

ليستي از كارمندان به همراه حقوق ماهيانه آن‌ها در دست است. اكنون نياز به گزارشي تحت وب، با مشخصات زير مي‌باشد:
1- گزارش بايد داراي صفحه بندي بوده و هر صفحه تنها 10 رديف را نمايش دهد.
2- سطرها بايد يك در ميان داراي رنگي متفاوت باشند.
3- ستون حقوق كارمندان در پايين هر صفحه، بايد داراي جمع باشد.
4- بتوان با كليك بر روي عنوان هر ستون، اطلاعات را بر اساس ستون انتخابي، مرتب ساخت.
5- لينك‌هاي حذف يا ويرايش يك رديف نيز در اين گزارش مهيا باشد.
6- ليست تهيه شده، داراي ستوني به نام «رديف» نيست. اين ستون را نيز به صورت خودكار اضافه كنيد.
7- ليست نهايي اطلاعات، داراي ستوني به نام ماليات نيست. فقط حقوق كارمندان ذكر شده است. ستون محاسبه شده ماليات نيز بايد به صورت خودكار در اين گزارش نمايش داده شود. اين ستون نيز بايد داراي جمع پايين هر صفحه باشد.
8- تمام اعداد اين گزارش در حين نمايش بايد داراي جدا كننده سه رقمي باشند.
9- تاريخ‌هاي موجود در ليست، ميلادي هستند. نياز است اين تاريخ‌ها در حين نمايش شمسي شوند.
10- انتهاي هر صفحه گزارش بايد بتوان برچسب «صفحه y/n» را مشاهده كرد. n در اينجا منظور تعداد كل صفحات است و y شماره صفحه جاري مي‌باشد.
11- انتهاي هر صفحه گزارش بايد بتوان برچسب «ركوردهاي y تا x از n» را مشاهده كرد. n در اينجا منظور تعداد كل ركوردها است.
12- نام كوچك هر كارمند، ضخيم نمايش داده شود.
13- به ازاي هر شماره كارمندي، يك تصوير در پوشه images سايت وجود دارد. براي مثال images/id.jpg. ستوني براي نمايش تصوير متناظر با هر كارمند نيز بايد اضافه شود.
14- به ازاي هر كارمند، تعدادي پروژه هم وجود دارد. پروژه‌هاي متناظر را توسط يك گريد تو در تو نمايش دهيد.


راه حل به كمك استفاده از WebGrid

ابتدا يك پروژه خالي ASP.NET MVC را آغاز كنيد. سپس مدل‌هاي زير را به آن اضافه نمائيد (يك كارمند كه مي‌تواند تعداد پروژه منتسب داشته باشد):

using System;
using System.Collections.Generic;

namespace MvcApplication17.Models
{
    public class Employee
    {
        public int Id { set; get; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public DateTime AddDate { get; set; }
        public double Salary { get; set; }
        public IList<Project> Projects { get; set; }
    }
}

namespace MvcApplication17.Models
{
    public class Project
    {
        public int Id { set; get; }
        public string Name { set; get; }
    }
}

سپس منبع داده نمونه زير را به پروژه اضافه كنيد. به عمد از ORM‌ خاصي استفاده نشده تا بتوانيد پروژه جاري را به سادگي در يك پروژه آزمايشي جديد،‌ تكرار كنيد.
using System;
using System.Collections.Generic;

namespace MvcApplication17.Models
{
    public static class EmployeeDataSource
    {
        public static IList<Employee> CreateEmployees()
        {
            var list = new List<Employee>();
            var rnd = new Random();
            for (int i = 1; i <= 1000; i++)
            {
                list.Add(new Employee
                    {
                        Id = i + 1000,
                        FirstName = "fName " + i,
                        LastName = "lName " + i,
                        AddDate = DateTime.Now.AddYears(-rnd.Next(1, 10)),
                        Salary = rnd.Next(400, 3000),
                        Projects = CreateRandomProjects()
                    });
            }
            return list;
        }

        private static IList<Project> CreateRandomProjects()
        {
            var list = new List<Project>();
            var rnd = new Random();
            for (int i = 0; i < rnd.Next(1, 7); i++)
            {
                list.Add(new Project
                {
                    Id = i,
                    Name = "Project " + i
                });
            }
            return list;
        }
    }
}


در ادامه يك كنترلر جديد را با محتواي زير اضافه نمائيد:
using System.Web.Mvc;
using MvcApplication17.Models;

namespace MvcApplication17.Controllers
{
    public class HomeController : Controller
    {
        [HttpPost]
        public ActionResult Delete(int? id)
        {
            return RedirectToAction("Index");
        }

        [HttpGet]
        public ActionResult Edit(int? id)
        {
            return View();
        }

        [HttpGet]
        public ActionResult Index(string sort, string sortdir, int? page = 1)
        {
            var list = EmployeeDataSource.CreateEmployees();
            return View(list);
        }
    }
}

علت تعريف متد index با پارامترهاي sort و غيره به URLهاي خودكاري از نوع زير بر مي‌گردد:

http://localhost:3034/?sort=LastName&sortdir=ASC&page=3

همانطور كه ملاحظه مي‌كنيد، گريد رندر شده، از يك سري كوئري استرينگ براي مشخص سازي صفحه جاري، يا جهت مرتب سازي (صعودي و نزولي بودن آن) يا فيلد پيش فرض مرتب سازي، كمك مي‌گيرد.

سپس يك View خالي را نيز براي متد Index ايجاد كنيد. تا اينجا تنظيمات اوليه پروژه انجام شد.
كدهاي كامل View را در ادامه ملاحظه مي‌كنيد:

@using System.Globalization
@model IList<MvcApplication17.Models.Employee>
           
@{
    ViewBag.Title = "Index";
}

@helper WebGridPageFirstItem(WebGrid grid)
{
    @(((grid.PageIndex + 1) * grid.RowsPerPage) - (grid.RowsPerPage - 1));
}

@helper WebGridPageLastItem(WebGrid grid)
{
    if (grid.TotalRowCount < (grid.PageIndex + 1 * grid.RowsPerPage))
    {
      @grid.TotalRowCount;
    }
    else
    {
      @((grid.PageIndex + 1) * grid.RowsPerPage);
    }
}

<h2>Employees List</h2>

@{ 
    var grid = new WebGrid(
        source: Model,
        canPage: true,
        rowsPerPage: 10,
        canSort: true,
        defaultSort: "FirstName"
    );
    var salaryPageSum = 0;
    var taxPageSum = 0;
    var rowIndex = ((grid.PageIndex + 1) * grid.RowsPerPage) - (grid.RowsPerPage - 1);
}

<div id="container">
    @grid.GetHtml(
            tableStyle: "webgrid",
            headerStyle: "webgrid-header",
            footerStyle: "webgrid-footer",
            alternatingRowStyle: "webgrid-alternating-row",
            selectedRowStyle: "webgrid-selected-row",
            rowStyle: "webgrid-row-style",
            htmlAttributes: new { id = "MyGrid" },
            mode: WebGridPagerModes.All,
            columns: grid.Columns(
                 grid.Column(header: "#",
                             style: "text-align-center-col",
                             format: @<text>@(rowIndex++)</text>),
                 grid.Column(columnName: "FirstName", header: "First Name",
                             format: @<span style='font-weight: bold'>@item.FirstName</span>,
                             style: "text-align-center-col"),
                 grid.Column(columnName: "LastName", header: "Last Name"),
                 grid.Column(header: "Image",
                             style: "text-align-center-col",
                             format: @<text><img alt="@item.Id" src="@Url.Content("~/images/" + @item.Id + ".jpg")" /></text>),
                 grid.Column(columnName: "AddDate", header: "Start",
                             style: "text-align-center-col",
                             format: item =>
                             {
                                 int ym = item.AddDate.Year;
                                 int mm = item.AddDate.Month;
                                 int dm = item.AddDate.Day;
                                 var persianCalendar = new PersianCalendar();
                                 int ys = persianCalendar.GetYear(new DateTime(ym, mm, dm, new GregorianCalendar()));
                                 int ms = persianCalendar.GetMonth(new DateTime(ym, mm, dm, new GregorianCalendar()));
                                 int ds = persianCalendar.GetDayOfMonth(new DateTime(ym, mm, dm, new GregorianCalendar()));
                                 return ys + "/" + ms.ToString("00") + "/" + ds.ToString("00");

                             }),
                 grid.Column(columnName: "Salary", header: "Salary",
                             format: item =>
                             {
                                 salaryPageSum += item.Salary;
                                 return string.Format("${0:n0}", item.Salary);
                             },
                             style: "text-align-center-col"),
                 grid.Column(header: "Tax", canSort: true,
                             format: item =>
                             {
                                 var tax = item.Salary * 0.2;
                                 taxPageSum += tax;
                                 return string.Format("${0:n0}", tax);
                             }),
                 grid.Column(header: "Projects", columnName: "Projects",
                             style: "text-align-center-col",
                             format: item =>
                             {
                                 var subGrid = new WebGrid(
                                                        source: item.Projects,
                                                        canPage: false,
                                                        canSort: false
                                                        );
                                 return subGrid.GetHtml(
                                                        htmlAttributes: new { id = "MySubGrid" },
                                                        tableStyle: "webgrid",
                                                        headerStyle: "webgrid-header",
                                                        footerStyle: "webgrid-footer",
                                                        alternatingRowStyle: "webgrid-alternating-row",
                                                        selectedRowStyle: "webgrid-selected-row",
                                                        rowStyle: "webgrid-row-style"
                                     );
                             }),
                 grid.Column(header: "",
                             style: "text-align-center-col",
                             format: item => @Html.ActionLink(linkText: "Edit", actionName: "Edit",
                                                              controllerName: "Home", routeValues: new { id = item.Id },
                                                              htmlAttributes: null)),
                 grid.Column(header: "",
                             format: @<form action="/Home/Delete/@item.Id" method="post"><input type="submit"
                                            onclick="return confirm('Do you want to delete this record?');"
                                            value="Delete"/></form>),
                 grid.Column(header: "", format: item => item.GetSelectLink("Select"))
                      )
                  )

    <strong>Page:</strong> @(grid.PageIndex + 1) / @grid.PageCount, 
    <strong>Records:</strong> @WebGridPageFirstItem(@grid) - @WebGridPageLastItem(@grid) of @grid.TotalRowCount

    @*
    @if (@grid.HasSelection)
    {
        @RenderPage("~/views/path/_partial_view.cshtml", new { Employee = grid.SelectedRow })
    }
    *@
</div>

@section script{
<script type="text/javascript">
    $(function () {
        $('#MyGrid tbody:first').append(
        '<tr class="total-row"><td></td>\
         <td></td><td></td><td></td>\
         <td><strong>Total:</strong></td>\
         <td>@string.Format("${0:n0}", @salaryPageSum)</td>\
         <td>@string.Format("${0:n0}", @taxPageSum)</td>\
         <td></td><td></td><td></td></tr>');
    });
</script>
}


توضيحات ريز جزئيات View فوق


تعريف ابتدايي شيء WebGrid و مقدار دهي آن
در ابتدا نياز است يك وهله از شيء WebGrid را ايجاد كنيم. در اينجا مي‌توان تنظيم كرد كه آيا نياز است اطلاعات نمايش داده شده داراي صفحه بندي (canPage) خودكار باشند؟ منبع داده (source) كدام است. در صورت فعال سازي صفحه بندي خودكار، چه تعداد رديف (rowsPerPage) در هر صفحه نمايش داده شود. آيا نياز است بتوان با كليك بر روي سر ستون‌ها، اطلاعات را بر اساس فيلد متناظر با آن مرتب (canSort) ساخت؟ همچنين در صورت نياز به مرتب سازي، اولين باري كه گريد نمايش داده مي‌شود، بر اساس چه فيلدي (defaultSort) بايد مرتب شده نمايش داده شود:

@{ 
    var grid = new WebGrid(
        source: Model,
        canPage: true,
        rowsPerPage: 10,
        canSort: true,
        defaultSort: "FirstName"
    );
    var salaryPageSum = 0;
    var taxPageSum = 0;
    var rowIndex = ((grid.PageIndex + 1) * grid.RowsPerPage) - (grid.RowsPerPage - 1);
}

در اينجا همچنين سه متغير كمكي هم تعريف شده كه از اين‌ها براي تهيه جمع ستون‌هاي حقوق و ماليات و همچنين نمايش شماره رديف جاري استفاده مي‌شود. فرمول نحوه محاسبه اولين رديف هر صفحه را هم ملاحظه مي‌كنيد. شماره رديف‌هاي بعدي، rowIndex++ خواهند بود.


تعريف رنگ و لعاب گريد نمايش داده شده
در ادامه به كمك متد grid.GetHtml، رشته‌اي معادل اطلاعات HTML صفحه جاري، بازگشت داده مي‌شود. در اينجا مي‌توان يك سري خواص تكميلي را تنظيم نمود. براي مثال:
tableStyle: "webgrid",
headerStyle: "webgrid-header",
footerStyle: "webgrid-footer",
alternatingRowStyle: "webgrid-alternating-row",
selectedRowStyle: "webgrid-selected-row",
rowStyle: "webgrid-row-style",
htmlAttributes: new { id = "MyGrid" },

هر كدام از اين رشته‌ها در حين رندر نهايي گريد،‌ تبديل به يك class خواهند شد. براي نمونه:

<div id="container">
      <table class="webgrid" id="MyGrid">
        <thead>
          <tr class="webgrid-header">

به اين ترتيب با اندكي ويرايش css سايت، مي‌توان انواع و اقسام رنگ‌ها را به سطرها و ستون‌هاي گريد نهايي اعمال كرد. براي مثال اطلاعات زير را به فايل css سايت اضافه نمائيد:

/* Styles for WebGrid
-----------------------------------------------------------*/
.webgrid
{
 width: 100%;
 margin: 0px;
 padding: 0px;
 border: 0px;
 border-collapse: collapse;
 font-family: Tahoma;
 font-size: 9pt;
}

.webgrid a
{
 color: #000;
}

.webgrid-header
{
 padding: 0px 5px;
 text-align: center;
 border-bottom: 2px solid #739ace;
 height: 20px;
 border-top: 2px solid #D6E8FF;
 border-left: 2px solid #D6E8FF;
 border-right: 2px solid #D6E8FF;
}

.webgrid-header th
{
 background-color: #eaf0ff;
 border-right: 1px solid #ddd;
}

.webgrid-footer
{
 padding: 6px 5px;
 text-align: center;
 background-color: #e8eef4;
 border-top: 2px solid #3966A2;
 height: 25px;
 border-bottom: 2px solid #D6E8FF;
 border-left: 2px solid #D6E8FF;
 border-right: 2px solid #D6E8FF;
}

.webgrid-alternating-row
{
 height: 22px;
 background-color: #f2f2f2;
 border-bottom: 1px solid #d2d2d2;
 border-left: 2px solid #D6E8FF;
 border-right: 2px solid #D6E8FF;
}

.webgrid-row-style
{
 height: 22px;
 border-bottom: 1px solid #d2d2d2;
 border-left: 2px solid #D6E8FF;
 border-right: 2px solid #D6E8FF;
}

.webgrid-selected-row
{
 font-weight: bold;
}

.text-align-center-col
{
 text-align: center;
}

.total-row
{
 background-color:#f9eef4;
}

همانطور كه ملاحظه مي‌كنيد، رنگ‌هاي رديف‌ها، هدر و فوتر گريد و غيره در اينجا تنظيم مي‌شوند.
به علاوه اگر دقت كرده باشيد در تعاريف گريد، htmlAttributes هم مقدار دهي شده است. در اينجا به كمك يك anonymously typed object، مقدار id گريد مشخص شده است. از اين id در حين كار با jQuery‌ استفاده خواهيم كرد.


تعيين نوع Pager
پارامتر ديگري كه در متد grid.GetHtml تنظيم شده است، mode: WebGridPagerModes.All مي‌باشد. WebGridPagerModes يك enum با محتواي زير است و توسط آن مي‌توان نوع Pager گريد را تعيين كرد:

[Flags]
public enum WebGridPagerModes
{
        Numeric = 1,
        //
        NextPrevious = 2,
        //
        FirstLast = 4,
        //
        All = 7,
}

نحوه تعريف ستون‌هاي گريد
اكنون به مهم‌ترين قسمت تهيه گزارش رسيده‌ايم. در اينجا با مقدار دهي پارامتر columns، نحوه نمايش اطلاعات ستون‌هاي مختلف مشخص مي‌گردد. مقداري كه بايد در اينجا تنظيم شود، آرايه‌اي از نوع WebGridColumn مي‌باشد و مرسوم است به كمك متد كمكي grid.Columns،‌ اينكار را انجام داد.
متد كمكي grid.Column، يك وهله از شيء WebGridColumn را بر مي‌گرداند و از آن براي تعريف هر ستون استفاده خواهيم كرد. توسط پارامتر columnName آن،‌ نام فيلدي كه بايد اطلاعات ستون جاري از آن اخذ شود مشخص مي‌شود. به كمك پارامتر header،‌ عبارت سرستون متناظر تنظيم مي‌گردد. پارامتر format، مهم‌ترين و توانمندترين پارامتر متد grid.Column است:

grid.Column(columnName: "FirstName", header: "First Name",
                             format: @<span style='font-weight: bold'>@item.FirstName</span>,
                             style: "text-align-center-col"),
grid.Column(columnName: "LastName", header: "Last Name"),

پارامتر format، به نحو زير تعريف شده است:

Func<dynamic, object> format

به اين معنا كه هر بار پيش از رندر سطر جاري، زمانيكه قرار است سلولي رندر شود، يك شيء dynamic در اختيار شما قرار مي‌گيرد. اين شيء dynamic يك ركورد از اطلاعات Model جاري است. به اين ترتيب به اطلاعات تمام سلول‌هاي رديف جاري دسترسي خواهيم داشت. بر اين اساس هر نوع پردازشي را كه لازم بود، انجام دهيد (شبيه به فرمول نويسي در ابزارهاي گزارش سازي، اما اينبار با كدهاي سي شارپ) و مقدار فرمت شده نهايي را به صورت يك رشته بر گردانيد. اين رشته نهايتا در سلول جاري درج خواهد شد.
اگر از پارامتر فرمت استفاده نشود، همان مقدار فيلد جاري بدون تغييري رندر مي‌گردد.
حداقل به دو نحو مي‌توان پارامتر فرمت را مقدار دهي كرد:

format: @<span style='font-weight: bold'>@item.FirstName</span>
or
format: item =>
                     {
                          salaryPageSum += item.Salary;
                           return string.Format("${0:n0}", item.Salary);
                      }

مستقيما از توانمندي‌هاي Razor استفاده كنيد. مثلا يك تگ كامل را بدون نياز به محصور سازي آن بين "" شروع كنيد. سپس @item به وهله‌اي از ركورد در دسترس اشاره مي‌كند كه در اينجا وهله‌اي از شيء كارمند است.
و يا همانند روشي كه براي محاسبه جمع حقوق هر صفحه مشاهده مي‌كنيد، مستقيما از lambda expressions براي تعريف يك anonymous delegate استفاده كنيد.


نحوه اضافه كردن ستون رديف
ستون رديف، يك ستون محاسبه شده (calculated field) است:

grid.Column(header: "#",
                 style: "text-align-center-col",
                 format: @<text>@(rowIndex++)</text>),

نيازي نيست حتما يك grid.Column، به فيلدي در كلاس كارمند اشاره كند. مقدار سفارشي آن را به كمك پارامتر format تعيين خواهيم كرد. هر بار كه قرار است يك رديف رندر شود، يكبار اين پارامتر فراخواني خواهد شد. فرمول محاسبه rowIndex ابتداي صفحه را نيز پيشتر ملاحظه نموديد.


نحوه اضافه كردن ستون سفارشي تصاوير كارمندها
ستون تصوير كارمندها نيز مستقيما در كلاس كارمند تعريف نشده است. بنابراين مي‌توان آن‌را با مقدار دهي صحيح پارامتر format ايجاد كرد:

grid.Column(header: "Image",
                  style: "text-align-center-col",
                  format: @<text><img alt="@item.Id" src="@Url.Content("~/images/" + @item.Id + ".jpg")" /></text>),


در اين مثال، تصاوير كارمندها در پوشه images واقع در ريشه سايت، قرار دارند. به همين جهت از متد Url.Content براي مقدار دهي صحيح آن استفاده كرديم. به علاوه در اينجا @item.Id به Id ركورد در حال رندر اشاره مي‌كند.


نحوه تبديل تاريخ‌ها به تاريخ شمسي
در ادامه بازهم به كمك پارامتر format، يك وهله از شيء dynamic اشاره كننده به ركورد در حال رندر را دريافت مي‌كنيم. سپس فرصت خواهيم داشت تا بر اين اساس، فرمول نويسي كنيم. دست آخر هم رشته مورد نظر نهايي را بازگشت مي‌دهيم:

grid.Column(columnName: "AddDate", header: "Start",
                  style: "text-align-center-col",
                  format: item =>
                  {
                       int ym = item.AddDate.Year;
                       int mm = item.AddDate.Month;
                       int dm = item.AddDate.Day;
                       var persianCalendar = new PersianCalendar();
                       int ys = persianCalendar.GetYear(new DateTime(ym, mm, dm, new GregorianCalendar()));
                       int ms = persianCalendar.GetMonth(new DateTime(ym, mm, dm, new GregorianCalendar()));
                       int ds = persianCalendar.GetDayOfMonth(new DateTime(ym, mm, dm, new GregorianCalendar()));
                       return ys + "/" + ms.ToString("00") + "/" + ds.ToString("00");
                    }),


اضافه كردن ستون سفارشي ماليات
در كلاس كارمند، خاصيت حقوق وجود دارد اما ماليات خير. با توجه به آن مي‌توانيم به كمك پارامتر format، به اطلاعات شيء dynamic در حال رندر دسترسي داشته باشيم. بنابراين به اطلاعات حقوق دسترسي داريم و سپس با كمي فرمول نويسي، مقدار نهايي مورد نظر را بازگشت خواهيم داد. همچنين در اينجا مي‌توان نحوه بازگشت مقدار حقوق را به صورت رشته‌اي حاوي جدا كننده‌هاي سه رقمي نيز مشاهده كرد:

grid.Column(columnName: "Salary", header: "Salary",
                 format: item =>
                             {
                                 salaryPageSum += item.Salary;
                                 return string.Format("${0:n0}", item.Salary);
                             },
                             style: "text-align-center-col"),
grid.Column(header: "Tax", canSort: true,
                             format: item =>
                             {
                                 var tax = item.Salary * 0.2;
                                 taxPageSum += tax;
                                 return string.Format("${0:n0}", tax);
                             }),


اضافه كردن گرديد‌هاي تو در تو
متد Grid.GetHtml، يك رشته را بر مي‌گرداند. بنابراين در هر چند سطح كه نياز باشد مي‌توان يك گريد را بر اساس اطلاعات دردسترس رندر كرد و سپس بازگشت داد:

grid.Column(header: "Projects", columnName: "Projects",
                  style: "text-align-center-col",
                  format: item =>
                  {
                                 var subGrid = new WebGrid(
                                                        source: item.Projects,
                                                        canPage: false,
                                                        canSort: false
                                                        );
                                 return subGrid.GetHtml(
                                                        htmlAttributes: new { id = "MySubGrid" },
                                                        tableStyle: "webgrid",
                                                        headerStyle: "webgrid-header",
                                                        footerStyle: "webgrid-footer",
                                                        alternatingRowStyle: "webgrid-alternating-row",
                                                        selectedRowStyle: "webgrid-selected-row",
                                                        rowStyle: "webgrid-row-style"
                                     );
                       }),


در اينجا كار اصلي از طريق پارامتر format شروع مي‌شود. سپس به كمك item.Projects به ليست پروژه‌هاي هر كارمند دسترسي خواهيم داشت. بر اين اساس يك گريد جديد را توليد كرد و سپس رشته معادل با آن را به كمك متد subGrid.GetHtml دريافت و بازگشت مي‌دهيم. اين رشته در سلول جاري درج خواهد شد. به نوعي يك گزارش master detail يا sub report را توليد كرده‌ايم.


اضافه كردن دكمه‌هاي ويرايش، حذف و انتخاب
هر سه دكمه ويرايش، حذف و انتخاب در ستون‌هايي سفارشي قرار خواهند گرفت. بنابراين مقدار دهي header و format متد grid.Column كفايت مي‌كند:

grid.Column(header: "",
                  style: "text-align-center-col",
                   format: item => @Html.ActionLink(linkText: "Edit", actionName: "Edit",
                                                              controllerName: "Home", routeValues: new { id = item.Id },
                                                              htmlAttributes: null)),
grid.Column(header: "",
                  format: @<form action="/Home/Delete/@item.Id" method="post"><input type="submit"
                                            onclick="return confirm('Do you want to delete this record?');"
                                            value="Delete"/></form>),
grid.Column(header: "", format: item => item.GetSelectLink("Select"))


نكته جديدي كه در اينجا وجود دارد متد item.GetSelectLink مي‌باشد. اين متد جزو متدهاي توكار گريد است و كار آن بازگشت دادن شيء grid.SelectedRow مي‌باشد. اين شيء پويا، حاوي اطلاعات ركورد انتخاب شده است. براي مثال اگر نياز باشد اين اطلاعات به صفحه‌اي ارسال شود، مي‌توان از روش زير استفاده كرد:

@if (@grid.HasSelection)
    {
        @RenderPage("~/views/path/_partial_view.cshtml", new { Employee = grid.SelectedRow })
    }


نمايش برچسب‌هاي صفحه x از n و ركوردهاي x تا y از z
در يك گزارش خوب بايد مشخص باشد كه صفحه جاري، كدامين صفحه از چه تعداد صفحه كلي است. يا ركوردهاي صفحه جاري چه بازه‌اي از تعداد ركوردهاي كلي را تشكيل مي‌دهند. براي اين منظور چند متد كمكي به نام‌هاي WebGridPageFirstItem و WebGridPageLastItem تهيه شده‌اند كه آن‌ها را در ابتداي View ارائه شده، مشاهده نموديد:

<strong>Page:</strong> @(grid.PageIndex + 1) / @grid.PageCount, 
    <strong>Records:</strong> @WebGridPageFirstItem(@grid) - @WebGridPageLastItem(@grid) of @grid.TotalRowCount

نمايش جمع ستون‌هاي حقوق و ماليات در هر صفحه
گريد توكار همراه با ASP.NET MVC در اين مورد راه حلي را ارائه نمي‌دهد. بنابراين بايد اندكي دست به ابتكار زد. مثلا:

@section script{
<script type="text/javascript">
    $(function () {
        $('#MyGrid tbody:first').append(
        '<tr class="total-row"><td></td>\
         <td></td><td></td><td></td>\
         <td><strong>Total:</strong></td>\
         <td>@string.Format("${0:n0}", @salaryPageSum)</td>\
         <td>@string.Format("${0:n0}", @taxPageSum)</td>\
         <td></td><td></td><td></td></tr>');
    });
</script>
}

در اين مثال به كمك jQuery با توجه به اينكه id گريد ما MyGrid است، يك رديف سفارشي كه همان جمع محاسبه شده است، به tbody جدول نهايي توليدي اضافه مي‌شود. از tbody:first هم در اينجا استفاده شده است تا رديف اضافه شده به گريدهاي تو در تو اعمال نشود.
سپس فايل Views\Shared\_Layout.cshtml را گشوده و از section تعريف شده، براي مقدار دهي master page سايت، استفاده نمائيد:

<head>
    <title>@ViewBag.Title</title>
    <link href="@Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" />
    <script src="@Url.Content("~/Scripts/jquery-1.5.1.min.js")" type="text/javascript"></script>
    @RenderSection("script", required: false)
</head>