本文用 ASP.NET MVC 5 實作一個 GridView,功能包括: 分頁(paging)、關鍵字過濾(filtering)、排序(sorting)、AJAX 非同步執行,外觀上亦支援 Responsive Web Design (響應式網頁)。執行畫面,如下圖 1。

ASP.NET MVC 實作 GridView 及 paging 的做法有很多種,本文是參考幾篇 Code Project 的文章 [1]。 閱讀前先建立一個觀念,paging 有分「前端」、「後端」兩種,應避免混為一談,如下:
1、前端:指「使用者介面」,如:頁碼列,上一頁、下一頁…等按鈕。
2、後端:指「撈資料庫」的方式,如:使用 SQL Server 的 ROW_NUMBER 函數,或 T-SQL 語法 OFFSET-FETCH,去資料庫撈,畫面上該頁要呈現的資料。

本文使用的第三方元件:
1、jQuery datatables:用來處理上述的「前端」分頁,亦即用來呈現 Grid 表格的外觀、使用者介面,以及和使用者的互動 (除了 jQuery,還透過 bootstrap、CSS 及一支 Flash 動畫檔)。
2、datatables.mvc5:用來處理上述的「後端」分頁,亦即用來撈資料庫。並可避免像過去 WebForm 要自己撰寫,處理 paging 的 SQL 語句或 Stored Procedure。此外,此元件也支援 Controller 層的 strongly typed model。

-------------------------------------------------
本文的範例下載點:
http://files.cnblogs.com/files/WizardWu/170326.zip
範例使用 Visual Studio 2015 (只要能支援 ASP.NET MVC 5 即可),需要 SQL Server 的 Northwind 資料庫
-------------------------------------------------


圖 1 範例執行畫面

首先在 VS 2015 中,新增一個 Web「專案(project)」,並勾選 MVC 範本。

接著在 Models 層中,新增一個空的 C# 類別 Order.cs (本文是以 Orders 資料表為範例),並手動加入,想呈現在 GridView 中,各個欄位的 get/set accessor,如下方程式碼:

using System.ComponentModel.DataAnnotations;

namespace NorthwindPaging.Models
{
public class Order
{
public int OrderID { get; set; } [Display(Name = "客戶 ID")]
public string CustomerID { get; set; } [Display(Name = "員工 ID")]
public decimal EmployeeID { get; set; } [Display(Name = "運送國別")]
public string ShipCountry { get; set; } [Display(Name = "運送費用")]
public decimal Freight { get; set; }
}
}

接著打開 Models/IdentityModels.cs 這支檔案,裡面是 ASP.NET identity 2.0 的相關功能。我們加入以下這一行 Order 資料表的 property 程式:

public DbSet<Order> Orders { get; set; }    //自訂類別 Order

接著在 Controller 層,新增一個命名為 OrderController 的空白「控制器」。

附註: 本文範例,會使用 Entity Framework 的觀念及 DbSet、DbContext 等物件及 binding 功能,但不使用 .edmx 實體模型檔。

安裝 jQuery datatables

裝著要透過 NuGet 安裝 jQuery datatables,如下圖 2。

圖 2 安裝 jQuery datatables

安裝完後,會自動在專案的 Content、Scripts 資料夾底下,各產生一個 DataTables 資料夾,及相關的 .css、.swf、.js 檔案。

接下來我們要手動幫 jQuery datatables 做註冊的動作,在 App_Start/BundleConfig.cs 裡,加入以下兩段程式碼:

// jquery datataables js files
bundles.Add(new ScriptBundle("~/bundles/datatables").Include(
"~/Scripts/DataTables/jquery.dataTables.min.js",
"~/Scripts/DataTables/dataTables.bootstrap.js")); // jquery datatables css file
bundles.Add(new StyleBundle("~/Content/datatables").Include(
"~/Content/DataTables/css/dataTables.bootstrap.css"));

接著在 Views/Shared/_Layout.cshtml,加入以下兩行程式碼:

@Styles.Render("~/Content/datatables")
@Scripts.Render("~/bundles/datatables")
安裝 datatables.mvc5

裝著要透過 NuGet 安裝 datatables.mvc5,如下圖 3。

圖 3 安裝 datatables.mvc5

安裝完後,專案中會多出一個對 DataTables.Mvc.dll 的參考。

設定資料庫的連線

首先,在 Web.config 的資料庫連線字串 DefaultConnection 中,手動加入 Northwind 的連線設定。

接著,在 Controllers/OrderController.cs 加入以下的程式碼,以取得資料庫驗證及連線,供後續 Controller 的 Action 方法使用。

private ApplicationDbContext _dbContext;

public ApplicationDbContext DbContext
{
get
{
return _dbContext ?? HttpContext.GetOwinContext().Get<ApplicationDbContext>();
}
private set
{
_dbContext = value;
}
}
初始化 jQuery datatables

在 Views/Order 資料夾裡,加入一個空白的「檢視」,網頁命名為 OrderGridView (或任何名稱)。接著清空 OrderGridView.cshtml 的所有內容 (jQuery datatables 會自動產生 head、body 等 tag),手動加入以下 HTML tag:

<div class="row">
<div class="col-md-12">
<div class="panel panel-primary list-panel" id="list-panel">
<div class="panel-heading list-panel-heading">
<h1 class="panel-title list-panel-title">Orders 資料表</h1>
</div>
<div class="panel-body">
<table id="orders-data-table" class="table table-striped table-bordered" style="width:100%;"></table>
</div>
</div>
</div>
</div>

接著繼續在 OrderGridView.cshtml 裡,手動加入以下的程式,以便用 AJAX 方式,由 server-side 從資料庫撈出畫面上,該頁要呈現的資料:

@section Scripts
{
<script type="text/javascript">
var orderListVM;
$(function () {
orderListVM = {
dt: null, init: function () {
dt = $('#orders-data-table').DataTable({
"serverSide": true,
"processing": true,
"ajax": {
"url": "@Url.Action("Get","Order")"
},
"columns": [
{ "title": "Order ID", "data": "OrderID", "searchable": true },
{ "title": "Customer ID", "data": "CustomerID", "searchable": true },
{ "title": "Employee ID", "data": "EmployeeID", "searchable": true },
{ "title": "Ship Country", "data": "ShipCountry", "searchable": true },
{ "title": "Freight", "data": "Freight", "searchable": true }
],
"lengthMenu": [[10, 25, 50, 100], [10, 25, 50, 100]],
});
}
} // initialize the datatables
orderListVM.init(); });
</script>
}

上方程式碼中,serverSide": true,表示 paging、filtering、sorting 要依使用者每次的操作,從 server-side 去取得;而非一次將符合 SELECT WHERE 條件的資料全部撈出,再由 client-side 去處理 (若資料量過大,會拖垮效能)。
processing": true,表示在存取資料庫時,畫面上是否要顯示,載入時的 processing 特效及字樣。若不設定,預設為 false。 lengthMenu 表示每頁要顯示的資料筆數,本範例可讓使用者用 combo box 作選擇。

安裝 System.Linq.Dynamic

本範例的 sorting 有用到 Dynamic LINQ 的語法 (非必要,只是為了簡化 sorting 的程式碼),此功能要額外安裝。我們透過 NuGet 安裝 Dynamic LINQ,如下圖 4。


圖 4 安裝 Dynamic LINQ

撰寫 Controller 裡的 sorting、filtering、paging 功能

接下來撰寫 OrderController 裡,Get 這個 Action 方法,程式碼如下:

public ActionResult Get([ModelBinder(typeof(DataTablesBinder))] IDataTablesRequest requestModel)
{
IQueryable<Order> query = DbContext.Orders; //LINQ to Entites
var totalCount = query.Count(); //Order 資料表全部 830 筆 #region Filtering (使用者輸入關鍵字搜尋)
// Apply filters for searching (DataTables.Mvc.Search 類別)
if (requestModel.Search.Value != string.Empty)
{
var value = requestModel.Search.Value.Trim(); //filtering 功能 (欄位必須要 string,欄位 int、decimal 預設不行,因此加上ToString())
query = query.Where(o => o.OrderID.ToString().Contains(value) ||
o.CustomerID.Contains(value) ||
o.EmployeeID.ToString().Contains(value) ||
o.ShipCountry.Contains(value) ||
o.Freight.ToString().Contains(value)
);
} var filteredCount = query.Count(); //全部 830 筆 #endregion Filtering #region Sorting var sortedColumns = requestModel.Columns.GetSortedColumns();
var orderByString = String.Empty; foreach (var column in sortedColumns)
{
orderByString += orderByString != String.Empty ? "," : "";
orderByString += (column.Data) + (column.SortDirection == Column.OrderDirection.Ascendant ? " asc" : " desc");
}
//Dynamic LINQ
query = query.OrderBy(orderByString == string.Empty ? "OrderID asc" : orderByString); //預設的排序欄位、排序方式 #endregion Sorting #region Paging
query = query.Skip(requestModel.Start).Take(requestModel.Length); //Skip:起始index,Take:要撈的筆數(使用者可由下拉選單選擇) int i1 = query.Count(); //已用 SQL Server 的 OFFSET-FETCH 或 ROW_NUMBER(),過濾出畫面上該頁要顯示的 10 筆 //用 Select() 重新組裝我們需要的資料
var data = query.Select(order => new
{
OrderID = order.OrderID,
CustomerID = order.CustomerID,
EmployeeID = order.EmployeeID,
ShipCountry = order.ShipCountry,
Freight = order.Freight
}).ToList(); #endregion Paging int i2 = query.Count(); //
int i3 = data.Count(); //
int i4 = requestModel.Draw; //1、2、...(非頁數)
int i5 = requestModel.Start; //起始index,第1頁為0、第2頁為10、第4頁為30、...
int i6 = requestModel.Length; //10. tells how many records per page user wants to see which is also configurable by user using combo box
int i7 = filteredCount; // 830 筆
int i8 = totalCount; // 830 筆 //參數1:datatables.mvc5 的自訂類別 DataTablesResponse, 參數2:允許 HTTP GET 存取
return Json(new DataTablesResponse(requestModel.Draw, data, filteredCount, totalCount), JsonRequestBehavior.AllowGet);
}

ActionResult Get()

這個自訂的 Get 方法,回傳的是 JsonResult。其中第一個參數,是第三方元件 datatables.mvc5 的自訂類別 DataTablesResponse。若我們在前端 OrderGridView.cshtml 裡,所撰寫的對應 columns 沒錯的話,GridView 即可正常顯示資料。且由於 jQuery datatables 支援 Bootstrap,因此這個 GridView 外觀上亦支援 RWD (響應式網頁),以行動裝置瀏覽時,畫面會自動縮放。

GridView 訊息中文化

jQuery datatables 中的文字訊息是英文,若要改成中文,可自行開啟 Scripts\DataTables\jquery.dataTables.min.js 這支檔案,手動進行修改,執行結果如圖 1 左下方頁碼列的「顯示」字樣。

後端的分頁 T-SQL 語法

若我們開啟 SQL Profiler,觀察畫面上換頁時所執行的 T-SQL 語句,會發現 LINQ 已處理好資料庫撈資料時的「分頁」問題,可避免像過去 WebForm 時代,要自己撰寫,處理 paging 的 SQL 語句或 Stored Procedure [4]。

版工測試用的資料庫版本為 SQL Server 2016 版,因此「分頁」會自動引用 OFFSET-FETCH 語法。如下方 T-SQL 語句,分別為畫面上,Grid View 第一頁、第四頁的語法,起始 index 分別為 0、30,表示要從第 0 筆、第 30 筆開始,撈出 10 筆資料。

SELECT
[Extent1].[OrderID] AS [OrderID], [Extent1].[CustomerID] AS [CustomerID], [Extent1].[EmployeeID] AS [EmployeeID], [Extent1].[ShipCountry] AS [ShipCountry], [Extent1].[Freight] AS [Freight]
FROM [dbo].[Orders] AS [Extent1] ORDER BY [Extent1].[OrderID] ASC
OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY
SELECT
[Extent1].[OrderID] AS [OrderID], [Extent1].[CustomerID] AS [CustomerID], [Extent1].[EmployeeID] AS [EmployeeID], [Extent1].[ShipCountry] AS [ShipCountry], [Extent1].[Freight] AS [Freight]
FROM [dbo].[Orders] AS [Extent1] ORDER BY [Extent1].[OrderID] ASC
OFFSET 30 ROWS FETCH NEXT 10 ROWS ONLY
參考文章

[1] GridView with Server Side Filtering, Sorting and Paging in ASP.NET MVC 5 (server-side)
https://www.codeproject.com/Articles/1118363/GridView-with-Server-Side-Filtering-Sorting-and-Pa

[2] Grid with Server Side Advanced Search using JQuery DataTables in ASP.NET MVC 5 (server-side)
https://www.codeproject.com/Articles/1170086/Grid-with-Server-Side-Advanced-Search-using-JQuery

[3] Beginners Guide for Creating GridView in ASP.NET MVC 5 (client-side)
https://www.codeproject.com/Articles/1114208/Beginners-Guide-for-Creating-GridView-in-ASP-NET-M

相關文章

[4] ASP.NET 数据分页第一篇 - 探讨分页原理及 SQL Server 2005 的 ROW_NUMBER 函数
http://www.cnblogs.com/WizardWu/archive/2008/08/02/1258832.html

[5] ASP.NET 数据分页第二篇 - 范例下载
http://www.cnblogs.com/WizardWu/archive/2008/08/06/1261589.html
---------------------------------------------

ASP.NET MVC 5 實作 GridView 分頁的更多相关文章

  1. 【初学者指南】在ASP.NET MVC 5中创建GridView

    介绍 在这篇文章中,我们将会学习如何在 ASP.NET MVC 中创建一个 gridview,就像 ASP.NET Web 表单中的 gridview 一样.服务器端和客户端有许多可用的第三方库,这些 ...

  2. Gridview分頁保存選項

    #region //'Revision: 1.00 Created Date: 2013/08/02 Created ID: Una [#1300071]增加多選框 /// <summary&g ...

  3. C# gridview分頁導出excel

    #region 导出Excel方法 //导出到Excel按钮 protected void btnExport_Click(object sender, EventArgs e) { Export(& ...

  4. ASP.NET MVC 單元測試系列

    ASP.NET MVC 單元測試系列 (7):Visual Studio Unit Test 透過 Visual Studio 裡的整合開發環境 (IDE) 結合單元測試開發是再便利不過的了,在 Vi ...

  5. ASP.NET MVC的客户端验证:jQuery验证在Model验证中的实现

    在简单了解了Unobtrusive JavaScript形式的验证在jQuery中的编程方式之后,我们来介绍ASP.NET MVC是如何利用它实现客户端验证的.服务端验证最终实现在相应的ModelVa ...

  6. ASP.NET MVC 5 05 - 视图

    PS: 唉,这篇随笔国庆(2015年)放假前几天开始的,放完假回来正好又赶上年底,公司各种破事儿. 这尼玛都写跨年了都,真服了.(=_=#) 好几次不想写了都. 可是又不想浪费这么多,狠不下心删除.没 ...

  7. ASP.Net MVC开发基础学习笔记:三、Razor视图引擎、控制器与路由机制学习

    一.天降神器“剃须刀” — Razor视图引擎 1.1 千呼万唤始出来的MVC3.0 在MVC3.0版本的时候,微软终于引入了第二种模板引擎:Razor.在这之前,我们一直在使用WebForm时代沿留 ...

  8. 微信扫码支付+Asp.Net MVC

    这里的扫码支付指的是PC网站上面使用微信支付,也就是官方的模式二,网站是Asp.net MVC,整理如下.(demo在最下方) 一.准备工作 使用的微信API中的统一下单方法,关键的参数是‘公众账号I ...

  9. ASP.NET MVC对WebAPI接口操作(添加,更新和删除)

    昨天<怎样操作WebAPI接口(显示数据)>http://www.cnblogs.com/insus/p/5670401.html 既有使用jQuery,也有使作HttpClient来从数 ...

随机推荐

  1. Asp.Net Core 轻松学-正确使用分布式缓存

    前言     本来昨天应该更新的,但是由于各种原因,抱歉,让追这个系列的朋友久等了.上一篇文章 在.Net Core 使用缓存和配置依赖策略 讲的是如何使用本地缓存,那么本篇文章就来了解一下如何使用分 ...

  2. Java虚拟机二:使用jvisualvm工具远程监控tomcat内存

    jdk中自带了很多工具可以用于性能分析,位于jdk的bin目录下,jvisualvm工具可以以图形化的方式更加直观的监控本地以及远程的java进程的内存占用,线程状态等信息. 一.配置tomcat 在 ...

  3. 【spring实战第五版遇到的坑】第14章spring.cloud.config.uri和token配置项无效

    本文使用的Spring Boot版本为:2.1.4.RELEASE Spring Cloud版本为:Greenwich.SR1 按照书上的做法,在application.yml中配置配置服务器的地址和 ...

  4. 【代码总结● Swing中的一些操作与设置】

    Swing中设置关闭窗口验证与添加背景图片 package com.swing.test; import java.awt.EventQueue; import java.awt.Image; imp ...

  5. jQuery中对未来的元素绑定事件用 on

    最近项目需要点击弹窗里面的a标签出现外连接跳转提示 <a href="javascript:void(0);" target="_blank" id=&q ...

  6. 解决git Failed to connect to 127.0.0.1 port xxxx: Connection refused

    某天,用git拉取,提交代码的时候出现了git Failed to connect to 127.0.0.1 port xxxx: Connection refused的问题, 开始百度,看了一通.都 ...

  7. 【English EMail】2019 Q2 Public Holiday Announcement

    Hi all, According to 2019 public holiday announcement released by Chinese government, this is to ann ...

  8. Storm入门(十一)Twitter Storm源代码分析之CoordinatedBolt

    作者: xumingming | 可以转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明网址: http://xumingming.sinaapp.com/811/twitter-stor ...

  9. Flarum轻量级论坛的安装

    论坛作为互联网中的远古产物,经历了如QQ群.社区和贴吧等新兴社交工具的冲击,依然能够存在,肯定是有着不可替代的用处,像吾爱.远景等论坛依旧火热.一些博客主也喜欢自己搭建一个论坛作为用户聚集之地. 之前 ...

  10. 学python走过的坑 三 不能实现的浏览器缩放功能

    公司一个项目,在启动web页面时,默认应该是打开项目页面,然后浏览器启动时总是打开一个广告页面,经理让写一个脚本,让电脑每次开机自启浏览器,且加载项目页面.浏览器自启和打开项目页面轻松搞定,这时问题来 ...