【问题标题】:Telerik MVC Grid not grouping properlyTelerik MVC Grid 未正确分组
【发布时间】:2011-06-30 20:27:46
【问题描述】:

我正在使用 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>

有什么想法吗?

【问题讨论】:

  • 糟糕...是的,我将其交叉发布到 Telerik 并且在复制之前没有擦洗。我已经找到了解决方案,我只需要组织它,然后我就可以在 SO 上发布它。
  • @Jush,咳咳……你有解决办法吗?我很想看看。
  • @Levitikon,检查我发布的答案。

标签: asp.net-mvc asp.net-mvc-3 telerik-mvc


【解决方案1】:

这里问题的症结在于我正在做 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 可能具有 AddressStreetAddressCity 的属性名称。我的IPropertyTranslator 接口指定了一个翻译过程,我可以从GridCommand 对象中的字符串排序成员名称转到我的域所期望的。

倒数第二个方法中的 Order 类是 NHibernate Order。此方法用于生成Order 对象列表,当我检索结果时传递给我的服务层。 ViewOrder 是我在 UI 中使用的实用程序类。我仍然需要重构最后两个方法,因为它们是重复的。

以下是我如何使用该帮助程序类为网格拉取GridModel 的示例:

    public GridModel GetAllOrdersGrid(GridCommand command)
    {
        var svc = DependencyResolver.Current.GetService<IOrderService>();

        var propertyTranslator = new OrdersViewModelTranslator();
        var orders =
            propertyTranslator.GenerateOrderList(command).ToList();

        IFutureValue<long> total;
        var orders = svc.FindAll(((command.Page - 1) * command.PageSize), command.PageSize, orders, out total);

        var mapper = new Mapper<DomainOrder, OrdersViewModel>();
        var viewModels = orders.Select(mapper.MapToViewModel);


        return command.GroupDescriptors.Any()
                   ? new GridModel
                   {
                       Data = TelerikGridHelpers.ApplyGrouping(viewModels.AsQueryable(), command.GroupDescriptors),
                       Total = Convert.ToInt32(total.Value)
                   }
                   : new GridModel { Data = viewModels, Total = Convert.ToInt32(total.Value) };
    }

其中有一点与整个分组问题无关,但这是一个真实的例子,所以也许会有所帮助。

【讨论】:

  • 好东西!真的帮了我
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多