Это не ответ, просто некоторый исходный код
В случае, если кому-то понадобится моя реализация jqGrid для ASP.NET WebForms, в свете того, что это довольно сложно реализовать, я опубликую код здесь.
Во-первых, некоторые классы JSON:
public class GridFilter
{
public string groupOp { get; set; }
public GridRule[] rules { get; set; }
}
public class GridRule
{
public string field { get; set; }
public string op { get; set; }
public string data { get; set; }
}
public class GridSettings
{
public bool IsSearch { get; set; }
public int PageSize { get; set; }
public int PageIndex { get; set; }
public string SortColumn { get; set; }
public string SortOrder { get; set; }
public GridFilter Where { get; set; }
}
Код переднего плана, я изменил некоторые из них, так что он позволяет мне публиковать в сервисе только с одним параметром, заполненным информацией Grid. Кроме того, мне не нужны отдельные фильтры, поэтому я просто поддерживаю режим нескольких фильтров (что, на мой взгляд, строго лучше).
<table id="UsersGrid"></table>
<div id="UsersGridPager"></div>
<script type="text/javascript">
$(document).ready(function () {
$('#UsersGrid').jqGrid({
colNames: ['ID', 'Online', 'Computer', 'IP', 'User'],
colModel: [
{ name: 'ID', width: 100, index: 'ID', searchoptions: { sopt: ['eq', 'ne']} },
{ name: 'IsOnline', width: 100, index: 'IsOnline', searchoptions: { sopt: ['eq', 'ne']} },
{ name: 'Name', index: 'Name', searchoptions: { sopt: ['eq', 'ne', 'cn']} },
{ name: 'IP', index: 'IP', searchoptions: { sopt: ['eq', 'ne', 'cn']} },
{ name: 'User', index: 'User', searchoptions: { sopt: ['eq', 'ne', 'cn']} }
],
jsonReader: {
root: function (json) { return JSON.parse(json.d).rows; },
page: function (json) { return JSON.parse(json.d).page; },
total: function (json) { return JSON.parse(json.d).total; },
records: function (json) { return JSON.parse(json.d).records; }
},
serializeGridData: jqGridSettings,
caption: "Usuarios",
emptyrecords: "No se encontraron usuarios",
url: "/GridTest/GridTestService.asmx/GetData",
ajaxGridOptions: { contentType: 'application/json; charset=utf-8' },
datatype: 'json',
mtype: 'POST',
height: 250,
rowNum: 10,
rowList: [10, 25, 50],
rownumbers: true,
autowidth: true,
pager: "#UsersGridPager"
}).navGrid("#UsersGridPager",
{
refresh: true,
add: false,
edit: false,
del: false,
search: true
},
{},
{},
{},
{
sopt: ["eq", "ne", "cn"],
multipleSearch: true,
showQuery: true
}
);
function jqGridSettings(p) {
var settings = {
grid: {
PageIndex: p.page,
PageSize: p.rows,
IsSearch: p._search,
SortColumn: p.sidx,
SortOrder: p.sord,
Where: jqGridFilters(p.filters)
}
};
return JSON.stringify(settings);
}
function jqGridFilters(json) {
var filters = {};
if (!json) {
return;
}
if (!json.length) {
return;
}
var parsed = JSON.parse(json);
if (!!parsed.rules) {
filters = parsed;
}
return filters;
}
});
Теперь для фактической реализации ... во-первых, нам понадобится пара методов расширения LINQ для упорядочения и сортировки данных. Это следующие:
public static IQueryable<T> OrderBy<T>(this IQueryable<T> query, string sortColumn, string direction)
{
if (string.IsNullOrEmpty(sortColumn))
return query;
string methodName = string.Format("OrderBy{0}",
direction.ToLower() == "asc" ? "" : "descending");
ParameterExpression parameter = Expression.Parameter(query.ElementType, "p");
MemberExpression memberAccess = null;
foreach (var property in sortColumn.Split('.'))
memberAccess = MemberExpression.Property(memberAccess ?? (parameter as Expression), property);
LambdaExpression orderByLambda = Expression.Lambda(memberAccess, parameter);
MethodCallExpression result = Expression.Call(
typeof(Queryable),
methodName,
new[] { query.ElementType, memberAccess.Type },
query.Expression,
Expression.Quote(orderByLambda));
return query.Provider.CreateQuery<T>(result);
}
public static IQueryable<T> Where<T>(this IQueryable<T> query, string column, object value, string operation)
{
if (string.IsNullOrEmpty(column))
return query;
ParameterExpression parameter = Expression.Parameter(query.ElementType, "p");
MemberExpression memberAccess = null;
foreach (var property in column.Split('.'))
memberAccess = MemberExpression.Property
(memberAccess ?? (parameter as Expression), property);
//change param value type
//necessary to getting bool from string
ConstantExpression filter = Expression.Constant
(
Convert.ChangeType(value, memberAccess.Type)
);
//switch operation
LambdaExpression lambda = null;
switch (operation)
{
case "eq": // equal
{
lambda = Expression.Lambda(Expression.Equal(memberAccess, filter), parameter);
break;
}
case "ne": // not equal
{
lambda = Expression.Lambda(Expression.NotEqual(memberAccess, filter), parameter);
break;
}
case "cn": // contains
{
Expression condition = Expression.Call(memberAccess,
typeof (string).GetMethod("Contains"),
Expression.Constant(value.ToString()));
lambda = Expression.Lambda(condition, parameter);
break;
}
}
var result = Expression.Call(
typeof(Queryable), "Where",
new[] { query.ElementType },
query.Expression,
lambda);
return query.Provider.CreateQuery<T>(result);
}
Фактическая реализация поиска, в порядке предпочтения, я поместил в свой класс GridSettings как метод-член, но это также может быть метод расширения для IQueryable.
public string SerializeQuery<T>(IQueryable<T> query, Func<T, List<string>> select)
{
//filtering
if (IsSearch && Where.rules != null)
{
if (Where.groupOp == "AND") // TODO: INSENSITIVE EQUALS, Y un enum GridGroupOperation.And.Name()
{
foreach (var rule in Where.rules)
query = query.Where(rule.field, rule.data, rule.op);
}
else if (Where.groupOp == "OR") // TODO: INSENSITIVE EQUALS, Y un enum GridGroupOperation.Or.Name()
{
var temp = (new List<T>()).AsQueryable();
foreach (var rule in Where.rules)
{
var t = query.Where(rule.field, rule.data, rule.op);
temp = temp.Concat(t);
}
//remove repeat records
query = temp.Distinct();
}
}
//sorting
query = query.OrderBy(SortColumn, SortOrder);
//count
var totalCount = query.Count();
//paging
var data = query.Skip((PageIndex - 1) * PageSize).Take(PageSize);
//convert to grid format
var result = new
{
total = (int)Math.Ceiling((double)totalCount / PageSize),
page = PageIndex,
records = totalCount,
rows = data.Select((d, id) => new { id, cell = select(d) }).ToArray()
};
return JsonConvert.SerializeObject(result);
}
Тогда для фактического обслуживания нам понадобятся следующие фрагменты:
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[ToolboxItem(false)]
[ScriptService]
public class GridTestService : System.Web.Services.WebService
{
[WebMethod]
[ScriptMethod]
public string GetData(GridSettings grid)
{
var query = new FakeComputersRepository().Computers();
var response = grid.SerializeQuery(query, d => new List<string>
{
d.ID.ToString(),
d.IsOnline.ToString(),
d.Name,
d.IP,
d.User
});
return response;
}
}
Как видите, я просто извлекаю данные, выбираю столбцы, которые я хочу отобразить (которые должны быть такими же и в том же порядке, что и в сетке на стороне клиента), и это почти все. Идея в том, чтобы это можно было использовать как можно больше.