本文用 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. .netcore2.1使用swagger显示接口说明文档

    项目之前开发完接口后,我们还需要写接口说明文档,现在有了swagger方便了很多,可以网页版直接测试,当然了也减少了我们的工作量. 使用swagger生成接口说明文档,大致需要2个步骤 1.从“管理 ...

  2. IdentityModel 中文文档(v1.0.0) 目录

    欢迎使用IdentityModel文档! 第一部分 协议客户端库 第1章 发现端点(Discovery Endpoint) 第2章 授权端点(Authorize Endpoint) 第3章 结束会话端 ...

  3. OAuth2.0记录

    阮一峰老师讲解OAuth2.0 http://www.ruanyifeng.com/blog/2014/05/oauth_2_0.html 举例详解: https://www.cnblogs.com/ ...

  4. vue表格实现固定表头首列

    前言 最近在做vue移动端项目,需要做一个可以固定表头首列的表格,而且由于一些原因不能使用任何UI插件,网上找了很久也没什么好方法,所以在解决了问题之后,写下了这篇文章供后来人参考,文章有什么错漏的问 ...

  5. HTML基础系列

    HTML标记语言,网页制作的第一步. 什么是HTML呢?查百度 基础语法 常用标签 HTML是超文本标记语言,HTML不用编译,直接在浏览器中执行,HTML是一个文本文件. HTML基本结构,标签,元 ...

  6. Android Studio 受不了了

    今天遇到一个问题,受不了了,来吐槽一下: Android Studio 里面创建两个工程:app, baselib.一个是App 一个是库.编译不过去. targetSdkVersion 26 imp ...

  7. oracle nid修改dbname

    修改name的目的只是为了日后管理清晰点,不重复.我比较懒.记性又差,所以就整理记下1.检查当前nameSQL> show parameter nameNAME TYPE VALUE------ ...

  8. Windows 2008 打开声音重定向来听到远程主机音频

    Windows 2008 Server在默认情况下,是禁止使用桌面桌面连接后播放声音的(提示音频服务未启用).可以通过下面的方法启用音频: 管理工具->远程桌面服务->远程桌面会话主机配置 ...

  9. ambari2.6.50 openssl 版本问题:SSLError: Failed to connect. Please check openssl library versions. Openssl error upon host registration

    I'm trying to register hostnames in Ambari but getting the error below. We tried to run yum update o ...

  10. Android 音视频同步机制

    一.概述 音视频同步(avsync),是影响多媒体应用体验质量的一个重要因素.而我们在看到音视频同步的时候,最先想到的就是对齐两者的pts,但是实际使用中的各类播放器,其音视频同步机制都比这些复杂的多 ...