在 ASP.NET 中使用 JqGrid
如何在 ASP.NET 中集成 JqGrid。
引言
大家好,我又回来了,带来了冰山一角。
寻找冰山大小和体积的责任是您的。这次的冰山是 JqGrid。你们可能认为 JqGrid 不是什么新东西,那为什么......对吧?没错,JqGrid 插件不是什么新东西。它在开源世界中是一个经过验证的数据显示控件,并得到 AJAX 的广泛支持。JqGrid 的优点在于其分页、排序、搜索等功能变得简单,并支持 JSON。
那么问题来了,我为什么要写这个...
我之所以撰写这篇文章,是因为我无法在网上找到任何概述 JqGrid 端到端集成的资源。
第二部分:JqGrid 行内编辑
让我思考 JqGrid 的问题
我正在开发一个拥有超过两百万用户的应用程序;在该应用程序中,有一个选项可以通过用户的名字、姓氏和 SSN 的最后四位数字搜索用户,我们使用我们的网格视图来显示搜索结果。
随着用户数量的增加,搜索结果也开始急剧增长,我们开始获得更多
相同组合的 300 多个搜索结果。
这使得用户很难找到确切的人或用户。建议的解决方案是在客户端提供更多的过滤或搜索功能。这里出现的下一个问题是,我们如何为现有网格添加这些功能,或者市场上有哪些控件提供这些功能。
这次搜索让我们找到了 JqGrid,它是一个免费控件,拥有所有上述功能,并且只需很少的编码工作即可完成。
关于 JqGrid 的几句话
- JqGrid 是一个时尚且功能丰富的表格数据呈现控件。
- JqGrid 是一个用于在 Web 上表示和操作表格数据的 JavaScript 控件。
- JqGrid 支持 Ajax。
- JqGrid 可以与任何服务器端技术集成,如 ASP、JavaServelets、JSP、PHP 等。
- JqGrid 由 Trirand Inc. 的 Tony Tomov 开发。
- JqGrid 与 ASP.NET 集成非常简单。
JqGrid 与 ASP.NET 集成逐步说明
- 从源代码下载 JqGrid。
- 将所需文件添加到 ASP.NET 应用程序(包括脚本和 CSS)。
- 在所需页面中初始化 JqGrid。
- 绑定数据。
正如我在第一点中提到的,您可以从 http://www.trirand.com/blog/?page_id=6 下载 JqGrid 和相关文件。
我尝试下载它,得到了一个名为 _jquery.jqGrid-4.5.2.zip_ 的 zip 文件。从 zip 文件的名称本身我就可以看出我下载的是 JqGrid 的 4.5.2 版本。
让我们解压并探索 zip 文件,看看里面都有什么。我发现里面有一些 CSS 文件夹、一些脚本文件夹等。让我们去看看我们可以利用哪些文件。为了让您更好地理解,我创建了一个名为 JQGridDemo 的演示应用程序来展示集成和功能。
我们主要需要的是 jQuery 文件,因为我们的主角依赖于 JavaScript 和 jQuery。
为了保存 JqGrid 相关文件,我在解决方案中创建了一个名为 JQGridReq 的文件夹。作为第一步,我将 jQuery 文件添加进去。
添加了 jQuery 1.9。我认为 1.9 jQuery 是 jQuery 最新的稳定版本。如果我们要使用 jQuery 的任何 UI 相关内容,接下来需要什么?是的,当然是 CSS 文件。但是我在文件夹中搜索了 jQuery CSS 文件,我找不到。没问题...好吧,我们来做一件事,从互联网上浏览并下载。
更好,对吧?
好的,最后我从互联网上找到了。_Jquery-ui-1.9.2.custom.css_,我们把它也添加到我们的应用程序中。请确保您还添加了相应的图像文件夹,因为我们正在添加 CSS,它可能也需要与 CSS 相关的图像。
所以我们现在已经准备好 jQuery 的东西了。
让我们开始逐个添加我们的 JqGrid 文件
- jquery.jqGrid-4.5.2\src\ jquery.jqGrid.js
- jquery.jqGrid-4.5.2\js\i18n\ grid.locale-en.js
- jquery.jqGrid-4.5.2\css\ ui.jqgrid.css
你注意到第二个文件了吗?它非常重要。我们也添加了 CSS 文件。现在我们已经完成了先决条件。您可以在下面的快照中看到我们添加的文件及其文件夹结构。
让我们转到 .aspx 页面来添加 JqGrid。
对于示例项目,我使用了一个简单的员工管理案例研究。从解决方案本身,您可以看出我正在使用母版页。所以我们要做的是,必须在母版页的 HTML 页面的 head 部分中调用所有必需的文件。
您可以在下面的部分中看到我在母版页的头部区域添加了什么。
好的,现在我所做的是,我直接进入我们计划放置 JqGrid 的页面。这里是 _Default.aspx_ 页面。
在该页面内放置了一个 ID 为 jQGridDemo 的 HTML 表格。(这个表格将充当我们的主角 JqGrid。)
我的意图是将表格转换为 JqGrid。这怎么可能呢?你以前使用过 jQuery 中的 Dialog 还是 JSON 吗?
算了...没问题。
我们必须将表初始化为 JqGrid,并包含我们计划在网格中显示的字段。这里我希望显示:
- ID
- 名字
- 姓氏
- SSN 后四位
- 部门
- 年龄
- 薪资
- 婚姻状况
- 地址。
您可以使用以下脚本将表格初始化为网格。
<script type="text/javascript">
jQuery("#jQGridDemo").jqGrid({
url: '',
datatype: "json",
colNames: ['Id','First Name', 'Last Name', 'Last 4 SSN', 'Department',
'Age', 'Salary', "Address",'Marital Status'],
colModel: [
{ name: '_id', index: '_id', width: 20, stype: 'text' },
{ name: 'FirstName', index: 'FirstName', width: 150 },
{ name: 'LastName', index: 'LastName', width: 150 },
{ name: 'LastSSN', index: 'LastSSN', width: 100 },
{ name: 'Department', index: 'Department', width: 80, align: "right" },
{ name: 'Age', index: 'Salary', width: 80, align: "right" },
{ name: 'Salary', index: 'Salary', width: 80, align: "right" },
{ name: 'Address', index: 'Address', width: 150, sortable: false },
{ name: 'MaritalStatus', index: 'MaritalStatus', width: 100, sortable: false }
],
rowNum: 10,
sortname: 'id',
viewrecords: true,
sortorder: "desc",
caption: "List Employee Details"
});
</script>
运行应用程序。您将看到一个样式化的网格,如下所示,但没有显示数据。
我想在网格显示后,你可以读懂我在用脚本初始化网格时写了什么,对吗?
colNames 是网格的标题。colModel 属性是一个 JSON 对象数据字段,用于配置网格的每一列。
我可以说它是要在网格中显示的数据模型,就像我们在数据集字段 `name.colNames` 属性中使用的那样,它应该与 colModel 属性中的项匹配。您可能已经注意到 url 属性留空了。为什么?而且您可能也想知道为什么网格中没有显示数据,对吗?对于这两个问题,我只能给您一个答案。那就是为了 AJAX 回调。
我将向您展示网格是如何填充数据的。
为了方便使用,我在这里使用 MongoDB 作为我的后端。这里出现的下一个问题是 URL 如何实现数据目的?
我所做的是,我创建了自定义 HTTP 处理程序,并且 HTTP 处理程序中的函数将获取员工记录并写入 HTTP 响应中。
HTTP 响应将是上述格式的 JSON 字符串。我们的 JqGrid 读取 JSON 响应,并借助前面提到的 colMode 在 JqGrid 中显示。您需要注意的一点是,我们现在正在处理 JSON 对象。JqGrid 可以处理 XML 数据、JSON 数据以及数组,这里我们使用 JSON。正如我所提到的,我创建了一个名为 _JQGridHandler.ashx_ 的 .ashx 处理程序。并提供了处理程序的 URL 为 _https://:58404/JQGridHandler.ashx_。我将在这里向您展示如何通过简单地调用 URL 从处理程序读取从网格传递的数据。像往常一样,如果我们向处理程序传递任何数据并从处理程序中读取它,我们会查看哪个参数?是的,我们肯定会首先查看 `context.Request`,对吗?这里我们也将搜索 Form 参数中是否传递了任何数据。
让我们调试看看。
通过查看调试器和我设置的监视,您可以看到我正在通过调用 `forms.Get("oper");` 来寻找一个名为 `oper` 的东西,我希望您也注意到 `Form{}`(它是一个数组)属性在这里是空的。
那么我怎么才能得到 `oper` 呢?是的,所以网格数据操作取决于 `oper` 参数。接下来我会向你展示 `oper` 中可能出现的所有数据。所以这里我推断如果 `oper==null`,那就是网格第一次加载。不要混淆。
我会在几秒钟内让你明白。这里我使用 MONGO 数据库作为我的数据存储。
你可以在 if 语句中看到数据获取代码。我希望到目前为止一切都清楚。
无论如何,我不会深入研究处理程序、JSON、Mongo 等,您可以使用任何数据库。只有连接和数据获取机制会不同。
我之所以使用 mongo 是因为它非常简单易用。好的,现在我们已经完成了 JqGrid 的所有必要设置,让我们看看它是否有效。
数据会填充到网格中吗?
运行它...
嘿,它运行得很好...
来吧,我们去开派对。 你能相信表格 jQGridDemo 会这样吗?是的,就是这样,这就是 JqGrid...那么现在你可能会想,这个网格有什么特别之处...作为一个简单的网格视图而已...你注意到“名字”列标题上出现了可排序符号了吗?我们为它编写代码了吗?是的...
这就是网格的魅力所在。不仅是“名字”列,对于每一列,点击列标题,你都会在顶部列标题上看到排序按钮。
除非你添加一个如下所示的属性。
{name: 'Address', index: 'Address', width: 150, sortable: false}
(在此示例中,地址字段不可排序)这只是一个示例。
接下来您可以看到类似这样的现有功能。请系好安全带...
你准备好在 JqGrid 表格(`jQGridDemo`)底部再添加一个 div 了吗?我来给你展示魔术。去添加它...
<table id="jQGridDemo">
</table>
<div id="jQGridDemoPager">
</div>
是的,我在名为 `jQGridDemoPager` 的 div 底部添加了一个 div。脚本中的一些更改如下。
请注意突出显示的部分,它们是新添加的。
让我们看看我们的网格现在看起来怎么样。
带有刷新和搜索选项的分页栏出现了。
底部栏的优点是,对于搜索等操作,您甚至不需要编写一行代码。不仅是搜索,排序也一样。JqGrid 会为我们自动完成所有这些功能。
我们去尝试搜索。你注意到底部的搜索按钮了吗?搜索旁边还有一个刷新按钮。但是它的标签没有显示出来,对吗?
只是一个按钮而已。如果我们想给刷新按钮添加一个标签。只需打开 _grid.locale-en.js_ 文件并添加相应的文本即可。我将向你展示我是如何为该按钮添加标签的。
在该文件中有一个名为 `nav` 的部分,您可以在上面的图片中看到,其中有一个 `refreshtext`。最初它是空白的,添加您需要的文本。我在这里添加了“刷新”作为标签文本。
你注意到刷新按钮的标签现在变了吗?是的,它已经变了。还有另一种改变按钮标签的选项。
我之所以告诉你这种方法,是因为我想让你探索文件里面有什么。那么搜索弹出窗口呢?它很漂亮,对吧?而且我知道你也注意到了搜索条件,比如等于、不等于、开头是等等。你注意到了吗?
好的,请看上面的图片。你可以清楚地看到下拉列表中的搜索条件。有很多条件,无论如何,我不会在我们的 POC 中使用所有这些条件。我想删除所有这些不必要的条件。
如何做到?
如果你看过我之前提到的文件(_grid.locale-en.js_),你可能也在搜索部分看到了所有这些条件。
是的,搜索部分,他是唯一的罪魁祸首。让我们尝试删除它,看看会发生什么。
是的,我删除了那些不必要的搜索条件。如果您愿意,可以与上面的图片进行比较,同时检查搜索和排序是否如您预期那样进行。对我来说,它运行良好。
你们呢?:)我希望到这里为止几乎清楚了吧?我的下一个目的是让网格响应式。我们如何编辑网格?你认为这也可以不费吹灰之力完成吗?好吧,让我们看看。
JqGrid 编辑/添加/删除
在 JqGrid 中,所有事件和属性都是可配置的。这非常简单,但要小心。即使是很小的更改也可能使您的网格无法按预期工作。
要为您的网格提供上述功能,您必须按照我下面提到的确切顺序添加以下代码。
$('#jQGridDemo').jqGrid('navGrid', '#jQGridDemoPager',
{
edit: true,
add: true,
del: true,
search: true,
searchtext: "Search",
addtext: "Add",
edittext: "Edit",
deltext:"Delete"
},
{//EDIT EVENTS AND PROPERTIES GOES HERE },
{//ADD EVENTS AND PROPERTIES GOES HERE},
{//DELETE EVENTS AND PROPERTIES GOES HERE},
{//SEARCH EVENTS AND PROPERTIES GOES HERE}
);
我提到事件和属性的顺序有一个口诀。
在第一个大括号里你添加了一些参数为 true。请看下面的图片,这是我从上面代码片段中实际解释的部分。
这意味着在网格导航栏(底部栏)中,所有提到的按钮都将显示为下面提到的相应文本。
为了更好地理解,我用相同的颜色标记了。这一部分你必须在 JqGrid 初始化事件和参数之后显式声明。
让我们来看看网格,看看发生了哪些变化。
请看突出显示的区域。您可以看到所有按钮都已显示,这些按钮是您在上面代码段中设置为 true 的。让我们添加一条记录。
点击底部导航栏上的小 + 添加符号。会弹出一个小窗口,如下图所示。
填写完并点击保存按钮。会发生什么?什么都不会发生:)。因为你没有为编辑操作配置任何东西。
要执行编辑/删除和添加操作,您还必须在网格中设置另一个 URL 属性,即 editurl。这将调用 .ashx 处理程序来执行添加操作。
您必须设置 editurl: 'https://:58404/JQGridHandler.ashx'。在 caption 下面。
您可以查看图像 7 来定位标题的位置。填写表格,然后点击保存。让我们看看会发生什么...
我在处理程序中设置了一个调试器,以检查保存是否到达处理程序。我知道你可能会想,来自 UI 的数据如何到达处理程序以插入到数据库中。
是的...正如预期,在点击保存按钮后,调试器在处理程序中被捕获。
你能看到表单中有什么吗(`context.Request.Form`)?是的,正是我们想要的。要插入的数据作为键值对。你注意到现在是 oper=add 了吗?
所以我希望您现在对 `oper` 有了比我之前在将数据加载到网格时解释时更多的了解。而且键值对的键将是在网格中指定的键,如 FirstName、LastName、Age 等。
希望你明白了。
因此,当 `oper` 的值为 add 时,add if 条件内的代码将执行以将记录添加到数据库。如何从表单中读取值?这非常简单。
string strFirstName = forms.Get("FirstName").ToString();
如上所示,您可以从 HTTP 请求的表单属性中读取任何值,将 FirstName 替换为您想要的内容。添加成功后,处理程序将向 HTTP 响应写入一个成功字符串。该字符串将显示在网格上方的添加/编辑弹出窗口中,如下所示。
您能看到顶部红色 Div 中显示的消息“员工记录添加成功”吗?
此响应是由处理程序发送的,是用户定义的。
您可能会想,在插入后,客户端的哪个事件会接收来自服务器端的响应,对吗?
******************************************************
Complete Script
******************************************************
$('#jQGridDemo').jqGrid('navGrid', '#jQGridDemoPager',
{
edit: true,
add: true,
del: true,
search: true,
searchtext: "Search",
addtext: "Add",
edittext: "Edit",
deltext:"Delete"
},
{ //EDIT portion
//Can also set the width and height of the editing window as below commented way
//height: 300,
//width: 400,
//top: 50,
//left: 100,
//dataheight: 280,
closeOnEscape: true,//Closes the popup on pressing escape key
reloadAfterSubmit: true,
drag: true,
afterSubmit: function (response, postdata) {
if (response.responseText == "") {
$(this).jqGrid('setGridParam',
{ datatype: 'json' }).trigger('reloadGrid');//Reloads the grid after edit
return [true, '']
}
else {
$(this).jqGrid('setGridParam',
{ datatype: 'json' }).trigger('reloadGrid'); //Reloads the grid after edit
return [false, response.responseText]
//Captures and displays the response text on th Edit window
}
},
editData: {
EmpId: function () {
var sel_id = $('#jQGridDemo').jqGrid('getGridParam', 'selrow');
var value = $('#jQGridDemo').jqGrid('getCell', sel_id, '_id');
return value;
}
}
},
{//ADD portion
closeAfterAdd: true,//Closes the add window after add
afterSubmit: function (response, postdata) {
if (response.responseText == "") {
$(this).jqGrid('setGridParam',
{ datatype: 'json' }).trigger('reloadGrid')//Reloads the grid after Add
return [true, '']
}
else {
$(this).jqGrid('setGridParam',
{ datatype: 'json' }).trigger('reloadGrid')//Reloads the grid after Add
return [false, response.responseText]
}
}
},
{ //DELETE
closeOnEscape: true,
closeAfterDelete: true,
reloadAfterSubmit: true,
closeOnEscape: true,
drag: true,
afterSubmit: function (response, postdata) {
if (response.responseText == "") {
$("#jQGridDemo").trigger("reloadGrid", [{ current: true}]);
return [false, response.responseText]
}
else {
$(this).jqGrid('setGridParam', { datatype: 'json' }).trigger('reloadGrid')
return [true, response.responseText]
}
},
delData: {
EmpId: function () {
var sel_id = $('#jQGridDemo').jqGrid('getGridParam', 'selrow');
var value = $('#jQGridDemo').jqGrid('getCell', sel_id, '_id');
return value;
}
}
},
{//SEARCH
closeOnEscape: true
}
);
上面的代码本身就是自解释的。我已经在上面的代码片段中包含了编辑和删除的代码。
我想说的一件重要的事情是关于编辑。在执行编辑操作时,我们总是根据某个主键更新数据,对吧?这里的主键是 _id。(_id 是 employeeid)
在编辑或更新时,只有标记为可编辑的字段的数据才会传输到处理程序。不会传输任何额外数据。
如果你查看编辑窗口,其中 _id 没有显示或标记为可编辑(默认情况下,所有字段都是可编辑的,除非添加编辑参数),因此它不会在 `context.request.Form` 中传输到处理程序。
为了将该 _id(即 employeeid)从我们的 JqGrid 传递到服务器,我使用了 JqGrid 的 `editData` 属性。我们可以使用 JqGrid 的 `delData` 属性来传递 _id 以删除记录。
注意:不仅仅是 _id,您还可以借助 JSON 格式的 `editData,delData` 将任何额外数据传递给处理程序。
您可以在上面的 JS 代码中看到这一点。我必须提到的另一个重要提示是从 JqGrid 的特定单元格中获取数据。
var sel_id = $('#jQGridDemo').jqGrid('getGridParam', 'selrow');
//Gets the Id of selected row
var value = $('#jQGridDemo').jqGrid('getCell', sel_id, '_id');
//Gets the value of column of selectedrow.(_id is the na,e of the column).
*******************************************************
Code in HTTP handler
*******************************************************
public class JQGridHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
System.Collections.Specialized.NameValueCollection forms = context.Request.Form;
string strOperation = forms.Get("oper");
MONGOConnect objMC = new MONGOConnect();//Helper Class
var collectionEmployee =
objMC.GetMongoCollection("EMPLOYEE");//Gets Employee Collection
string strResponse = string.Empty;
if (strOperation == null)
{
//oper = null which means its first load.
var jsonSerializer = new JavaScriptSerializer();
context.Response.Write(jsonSerializer.Serialize(
collectionEmployee.AsQueryable<Employee>().ToList<Employee>()));
}
else if (strOperation == "del")
{
var query = Query.EQ("_id", forms.Get("EmpId").ToString());
collectionEmployee.Remove(query);
strResponse = "Employee record successfully removed";
context.Response.Write(strResponse);
}
else
{
string strOut=string.Empty;
AddEdit(forms, collectionEmployee, out strOut);
context.Response.Write(strOut);
}
}
public bool IsReusable
{
get
{
return false;
}
}
private void AddEdit(NameValueCollection forms,
MongoCollection collectionEmployee,out string strResponse)
{
string strOperation = forms.Get("oper");
string strEmpId = string.Empty;
if (strOperation == "add")
{
strEmpId = forms.Get("EmpId").ToString();
}
else if (strOperation == "edit")
{
var result = collectionEmployee.AsQueryable<Employee>().Select(c => c._id).Max();
strEmpId = (Convert.ToInt32(result) + 1).ToString();
}
string strFirstName = forms.Get("FirstName").ToString();
string strLastName = forms.Get("LastName").ToString();
string strLastSSN = forms.Get("LastSSN").ToString();
string strDepartment = forms.Get("Department").ToString();
string strAge = forms.Get("Age").ToString();
string strSalary = forms.Get("Salary").ToString();
string strAddress = forms.Get("Address").ToString();
string strMaritalStatus = forms.Get("MaritalStatus").ToString();
Employee objEmp = new Employee();
objEmp._id = strEmpId;
objEmp.FirstName = strFirstName;
objEmp.LastName = strLastName;
objEmp.LastSSN = strLastSSN;
objEmp.Department = strDepartment;
objEmp.Age = Convert.ToInt32(strAge);
objEmp.Address = strAddress;
objEmp.MaritalStatus = strMaritalStatus;
objEmp.Salary = strSalary;
collectionEmployee.Save(objEmp);
strResponse = "Employee record successfully updated";
}
}
根据 `strOperation(forms.Get("oper"))` 中的值,null、add、edit 和 del 将执行处理程序中的操作并发回自定义响应。仅此而已。
您可以看到删除操作是什么样子。
第二部分:JqGrid 行内编辑
第三部分: JqGrid 与 MVC
结论
JqGrid 是一个非常时尚且易于集成的网格,拥有许多令人惊叹的功能。
如果有人要求您在短时间内构建一个具有所有这些搜索、排序、过滤选项的应用程序,您可以非常放心地选择 JqGrid。
另外,我建议在快速应用程序开发中使用 MongoDB 会非常有用。对于这个演示应用程序,我使用 MongoDB 作为后端数据库,因此我能够很快完成。
如果您使用我们的网格视图和 SQL Server 进行开发,开发一个具有所有这些功能的应用程序需要多少小时?使用 JqGrid 开发所需时间要少得多,如果使用 MongoDB 则更少。我不是在推广 MongoDB,但这只是我根据经验写下来的。JqGrid 还有许多其他功能有待探索,这就是为什么我在介绍中提到它只是冰山一角。