我正在使用Telerik MVC Grid组件渲染通过ajax填充的可分组网格。网格呈现精细,排序和分页工作,ajax刷新工作,但当我尝试进行分组时,渲染变得全乱。附加的是网格预分组和分组后的屏幕截图。
网格定义非常简单:
<div id="tabAccounts" class="tab_content">
@(Html.Telerik().Grid<SharedSimpleAccountListViewModel>()
.Name("AcctGrid")
.Columns(columns =>
{
columns.Bound(x => x.Number)
.HeaderHtmlAttributes(new { @style = "text-align: center;" })
.HtmlAttributes(new { @style = "text-align: center;" });
columns.Bound(x => x.ProviderOrganizationFriendlyName)
.Title("Provider");
columns.Bound(x => x.Name)
.Title("Account Name");
columns.Bound(x => x.BillingLocationName)
.Title("Location");
})
.Groupable()
.DataBinding(db => db.Ajax().Select("CustomerAccounts", "Customers", new { id = Model.Id }))
.Pageable(pager => pager.PageSize(50))
.Sortable()
)
</div>
控制器操作也是直接的(我不会粘贴,因为它只是从存储库中检索)。我正在使用Telerik默认主题,因此没有自定义CSS,我已经确认页面中包含所需的脚本。
在分组后检查HTML,似乎对表进行了更改,但它没有为组添加表行元素。这是分组尝试后存在的HTML:
<table cellspacing="0">
<colgroup>
<col class="t-group-col">
<col><col><col><col>
</colgroup>
<thead class="t-grid-header">
<tr>
<th class="t-group-cell t-header"> </th>
<th style="text-align: center;" scope="col" class="t-header">
<a href="/Customers/Details/408?AcctGrid-orderBy=Number-asc" class="t-link">Number</a>
</th>
<th scope="col" class="t-header">
<a href="/Customers/Details/408?AcctGrid-orderBy=ProviderOrganizationFriendlyName-asc" class="t-link">Provider</a>
</th>
<th scope="col" class="t-header">
<a href="/Customers/Details/408?AcctGrid-orderBy=Name-asc" class="t-link">Account Name</a>
</th>
<th scope="col" class="t-header t-last-header">
<a href="/Customers/Details/408?AcctGrid-orderBy=BillingLocationName-asc" class="t-link">Location</a>
</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: center;">00002</td>
<td>Acme</td>
<td>Test account 2 </td>
<td class="t-last">Location 2</td>
</tr>
<tr class="t-alt">
<td style="text-align: center;">00001</td>
<td>3M</td>
<td>Test account 1</td>
<td class="t-last">Location 1</td>
</tr>
</tbody>
</table>
任何想法可能会在这里发生什么?
答案 0 :(得分:3)
问题的关键在于我正在进行AJAX绑定但是想要进行分组和排序。需要的是手动排序过程,首先按分组列排序,然后排序其他排序列。然后网格负责设置组UI。这对我来说是一个挑战,因为我的项目使用NHibernate作为ORM,具有处理查询的相当强大的服务层。我最终让网格与一个看起来像这样的助手类一起工作:
public static class TelerikGridHelpers
{
public static IEnumerable<AggregateFunctionsGroup> BuildInnerGroup<T, TObject>(IEnumerable<TObject> group, Func<TObject, T> groupSelector, Func<IEnumerable<TObject>, IEnumerable> innerSelector)
{
return group.GroupBy(groupSelector)
.Select(i => new AggregateFunctionsGroup
{
Key = i.Key,
Items = innerSelector(i)
});
}
public static Func<IEnumerable<TObject>, IEnumerable<AggregateFunctionsGroup>> BuildGroup<T, TObject>(Func<TObject, T> groupSelector, Func<IEnumerable<TObject>, IEnumerable<AggregateFunctionsGroup>> selectorBuilder)
{
var tempSelector = selectorBuilder;
return g => g.GroupBy(groupSelector)
.Select(c => new AggregateFunctionsGroup
{
Key = c.Key,
HasSubgroups = true,
Items = tempSelector.Invoke(c).ToList()
});
}
public static IEnumerable<AggregateFunctionsGroup> ApplyGrouping<T>(IQueryable<T> data, IList<GroupDescriptor> groupDescriptors)
{
Func<IEnumerable<T>, IEnumerable<AggregateFunctionsGroup>> selector = null;
foreach (var descriptor in groupDescriptors.Reverse())
{
var tempDescriptor = descriptor;
if (selector == null)
selector = g => BuildInnerGroup(g.Select(p => p), p => p.GetType().GetProperty(tempDescriptor.Member).GetValue(p, null), i => i.ToList());
else
selector = BuildGroup(p => p.GetType().GetProperty(tempDescriptor.Member).GetValue(p, null), selector);
}
return selector != null
? selector.Invoke(data).ToList()
: null;
}
public static List<Order> GenerateOrderList<T>(this T translator, GridCommand command) where T : IPropertyNameTranslator
{
var orders = new List<Order>();
// Step 1 is to add the grouping orders
if (command.GroupDescriptors.Any())
orders.AddRange(from descriptor in command.GroupDescriptors
let sortField = translator.TranslatePropertyToDomainProperty(descriptor.Member)
select descriptor.SortDirection == ListSortDirection.Ascending ? Order.Asc(sortField) : Order.Desc(sortField));
// Then the sorting
if (command.SortDescriptors.Any())
orders.AddRange(from descriptor in command.SortDescriptors.Where(c => !command.GroupDescriptors.Where(g => g.Member == c.Member).Any())
let sortField = translator.TranslatePropertyToDomainProperty(descriptor.Member)
select descriptor.SortDirection == ListSortDirection.Ascending ? Order.Asc(sortField) : Order.Desc(sortField));
return orders;
}
public static List<ViewOrder> GenerateViewOrderList<T>(this T translator, GridCommand command) where T : IPropertyNameTranslator
{
var orders = new List<ViewOrder>();
// Step 1 is to add the grouping orders
if (command.GroupDescriptors.Any())
orders.AddRange(from descriptor in command.GroupDescriptors
let sortField = translator.TranslatePropertyToDomainProperty(descriptor.Member)
select new ViewOrder { PropertyName = sortField, Ascending = descriptor.SortDirection == ListSortDirection.Ascending});
// Then the sorting
if (command.SortDescriptors.Any())
orders.AddRange(from descriptor in command.SortDescriptors.Where(c => !command.GroupDescriptors.Where(g => g.Member == c.Member).Any())
let sortField = translator.TranslatePropertyToDomainProperty(descriptor.Member)
select new ViewOrder { PropertyName = sortField, Ascending = descriptor.SortDirection == ListSortDirection.Ascending });
return orders;
}
}
请注意,我使用的是具有展平属性名称的ViewModel,因此如果我的域对象具有类型为Address
的属性,则ViewModel的属性名称可能为AddressStreet
和{{1} }。我的AddressCity
接口指定了一个转换过程,我可以从IPropertyTranslator
对象中的字符串排序成员名称转到我的域期望的名称。
倒数第二个方法中的GridCommand
类是NHibernate Order
。此方法用于生成我检索结果时传递给服务层的Order
个对象列表。 Order
是我在UI中使用的实用程序类。我仍然需要重构最后两种方法,因为它们是重复的。
以下是我如何使用该帮助程序类来为网格提取ViewOrder
的示例:
GridModel
那里有一点与分组的整个问题无关,但这是一个真实世界的例子,所以也许它会有所帮助。