ASP.NET MVC 5 實作 GridView 分頁
本文用 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 分頁的更多相关文章
- 【初学者指南】在ASP.NET MVC 5中创建GridView
介绍 在这篇文章中,我们将会学习如何在 ASP.NET MVC 中创建一个 gridview,就像 ASP.NET Web 表单中的 gridview 一样.服务器端和客户端有许多可用的第三方库,这些 ...
- Gridview分頁保存選項
#region //'Revision: 1.00 Created Date: 2013/08/02 Created ID: Una [#1300071]增加多選框 /// <summary&g ...
- C# gridview分頁導出excel
#region 导出Excel方法 //导出到Excel按钮 protected void btnExport_Click(object sender, EventArgs e) { Export(& ...
- ASP.NET MVC 單元測試系列
ASP.NET MVC 單元測試系列 (7):Visual Studio Unit Test 透過 Visual Studio 裡的整合開發環境 (IDE) 結合單元測試開發是再便利不過的了,在 Vi ...
- ASP.NET MVC的客户端验证:jQuery验证在Model验证中的实现
在简单了解了Unobtrusive JavaScript形式的验证在jQuery中的编程方式之后,我们来介绍ASP.NET MVC是如何利用它实现客户端验证的.服务端验证最终实现在相应的ModelVa ...
- ASP.NET MVC 5 05 - 视图
PS: 唉,这篇随笔国庆(2015年)放假前几天开始的,放完假回来正好又赶上年底,公司各种破事儿. 这尼玛都写跨年了都,真服了.(=_=#) 好几次不想写了都. 可是又不想浪费这么多,狠不下心删除.没 ...
- ASP.Net MVC开发基础学习笔记:三、Razor视图引擎、控制器与路由机制学习
一.天降神器“剃须刀” — Razor视图引擎 1.1 千呼万唤始出来的MVC3.0 在MVC3.0版本的时候,微软终于引入了第二种模板引擎:Razor.在这之前,我们一直在使用WebForm时代沿留 ...
- 微信扫码支付+Asp.Net MVC
这里的扫码支付指的是PC网站上面使用微信支付,也就是官方的模式二,网站是Asp.net MVC,整理如下.(demo在最下方) 一.准备工作 使用的微信API中的统一下单方法,关键的参数是‘公众账号I ...
- ASP.NET MVC对WebAPI接口操作(添加,更新和删除)
昨天<怎样操作WebAPI接口(显示数据)>http://www.cnblogs.com/insus/p/5670401.html 既有使用jQuery,也有使作HttpClient来从数 ...
随机推荐
- 浏览器插件使用socks5代理
服务端测试,经常会遇到需要通过代理访问的情景,比如公司内网不能访问测试环境,这时可以通过socks5代理来解决. 一.使用Chrome浏览器访问 1. 下载并安装SwitchyOmega插件 ...
- javascript入门篇(四)
Break 和 Continue 语句 break 它常用于跳出 switch() 语句, break 语句也可用于跳出循环.break 语句跳出循环后,会继续执行该循环之后的代码(如果有的话) co ...
- 3.App Inventor 2项目导入与导出
首先熟悉导入.导出项目是为了养成良好的备份习惯. 一.登陆App Inventor 2编程界面都大同小异,在项目菜单下面有导入项目和导出项目菜单. 二.打开导入项目界面,选择要导入的aia文件. 三. ...
- QT读取xml配置文件
//获取字符串字段 QString ConfigHelper::GetStringConfigValue(QString str) { if(str == "InitDeviceNo&quo ...
- Python第二十六天 python装饰器
Python第二十六天 python装饰器 装饰器Python 2.4 开始提供了装饰器( decorator ),装饰器作为修改函数的一种便捷方式,为工程师编写程序提供了便利性和灵活性装饰器本质上就 ...
- 记一发idea resources下rename的坑
resources rename文件 '.'不表示下级目录 只是作为一个字符 第一个com.uniubi.dao 是一层层创的.第二个是直接用idea 创的如下图. maven 打包后如下所示. ps ...
- Go基础(1)
demo1: package add var Name string = "hello world" var Age int = 10 package main import ( ...
- 从壹开始微服务 [ DDD ] 之七 ║项目第一次实现 & CQRS初探
前言 哈喽大家周五好,我们又见面了,感谢大家在这个周五读我的文章,经过了三周的时间,当然每周两篇的速度的情况下,咱们简单说了下DDD领域驱动设计的第一部分,主要包括了,<项目入门DDD架构浅析& ...
- Linux知识要点(文件压缩打包解压缩)
tar 的选项与参数非常的多!我们只讲几个常用的选项,更多选项您可以自行 man tar 查询啰! 其实最简单的使用 tar 就只要记忆底下的方式即可(gzip方式): 压 缩: tar -zcvf ...
- 让VS2019支持.NET Core WinForms和WPF设计器的临时办法(比微软给出的办法更方便)
参考以下代码片段,给项目添加NET Framework目标框架,切换到NET472运行时重新生成项目,然后打开设计器界面. 如果遇到设计器报错,尝试以NET472运行时为目标重新生成项目,并重新打开V ...