基于对象数组的Kendo Grid多列组

时间:2016-07-28 09:04:40

标签: asp.net-mvc razor kendo-grid

我对MVC(和Kendo)相对较新,但我设法使用columns.Group功能设置了包含多列标题的网格。

@(Html.Kendo().Grid<Result>()
            .Name("myGrid")
            .Columns(columns =>
            {
                columns.Bound(c => c.ResultDateTime).Title("Date Time");

                foreach (Lot Lot in (Lot[])ViewBag.Lots)                
                {
                    columns.Group(group => group
                        .Title(Lot.LotNumber)
                        .Columns(info =>
                        {
                            info.Bound(Lot.Result.Count.ToString());
                            info.Bound(Lot.Result.Mean.ToString());
                            info.Bound(Lot.Result.SD.ToString());
                        }));
                }
                columns.Bound(c => c.StandardComment.Description).Title("Comment");
                columns.Bound(c => c.ReviewComment.Description).Title("Review Comment");
                columns.Command(command => { command.Destroy(); });
            })
            .Editable(editable => editable
                .Mode(GridEditMode.InLine)
                .DisplayDeleteConfirmation(true))
            .Pageable()
            .Navigatable()
            .Sortable()
            .Groupable()
            .Scrollable()
            .DataSource(dataSource => dataSource
                .Ajax()
                .Batch(true)
                .PageSize(20)
                .ServerOperation(false)
                .Events(events => events.Error("error_handler"))
                .Read("ResultsAsync_Read", "ResultEntry")
                .Destroy("ResultsAsync_Destroy", "ResultEntry")
             )
        )

正如您所看到的,我正在尝试根据已使用ViewBag设置和传递的数组动态构建列。

Controller async函数,用于设置ViewBag.Lots从顶级IEnumerable<Result>对象中提取数组:

public async Task<ActionResult> ResultsAsync_Read([DataSourceRequest]DataSourceRequest request)
        {                
            IEnumerable<Result> controlSets = await _manager.ReadAsync(test);            
            ViewBag.Lots = controlSets.Select(x => x.LotResults);
            return Json(controlSets.ToDataSourceResult(request));
        }

运行此操作时,尝试访问ViewBag.Lots中的foreach属性时出现以下错误。

  

NullReferenceException:未将对象引用设置为的实例   对象

有人知道我为什么会收到此错误,是否有更有效的方法来实现我的目标?

修改 我使用它来保存整个Lot中可用的最大批量数,而不是使用ViewBag来保存List<Result>个对象的列表。 我已经在板上接受了@ ken2k的建议,并在控制器的Index()功能中完成了这项工作:

public async Task<IActionResult> Index()
        {
            QCTest test = new Models.Acusera.QCTest();
            test.TestID = 3;
            IEnumerable<Result> controlSets = await _manager.ReadAsync(test);
            ViewBag.MaxLots = controlSets.Max(x => x.LotResults.Count);
            return View("~/Views/Acusera/DataEntry/ResultEntry.cshtml");
        }

然后我循环可用的最大批次数并创建所需的列:

.Columns(columns =>
                {
                    columns.Bound(c => c.ResultDateTime).Title("Date Time");

                    for (int i = 0; i < ViewBag.MaxLots; ++i)
                    {
                        columns.Group(group => group
                            .Title("Test")
                            .Columns(info =>
                            {
                                info.Bound(x => x.LotResults[i].Result.Count);
                                info.Bound(x => x.LotResults[i].Result.Mean);
                                info.Bound(x => x.LotResults[i].Result.SD);
                            }));
                    }
                    columns.Bound(c => c.StandardComment.Description).Title("Comment");
                    columns.Bound(c => c.ReviewComment.Description).Title("Review Comment");
                    columns.Command(command => { command.Destroy(); });
                })

这会导致网格显示如下:

enter image description here

所以我设法创建了显示数据所需的多个标题列的数量。但是,我现在收到一个错误:

  

未捕获的TypeError:无法读取属性&#39;结果&#39;未定义的

1 个答案:

答案 0 :(得分:2)

您的ResultsAsync_Read方法是一种异步方法,由Kendo框架从javascript AJAX调用中调用,即页面加载并呈现后。

这意味着当您的网页呈现时,ViewBag.Lots实际上为空,这会抛出异常。

您需要在加载页面时初始化此值,而不是在ResultsAsync_Read方法中。基本上是:

public async Task<ActionResult> Index()
{
    // Gets the values BEFORE rendering the view
    IEnumerable<Result> controlSets = await _manager.ReadAsync(test);

    // The ViewBag property will be available from the Razor view            
    ViewBag.Lots = controlSets.Select(x => x.LotResults);

    // Returns the view that display the grid
    return this.View();
}

记住MVC的实际工作方式非常重要。基本上步骤是:

  • 服务器在... / Index route
  • 上收到请求
  • 服务器执行Index()动作
  • 当动作返回this.View()(它等同于this.View(&#34;索引&#34;)),它呈现Index.cshtml剃刀视图(这意味着ViewBag必须不为null这里)
  • 如果稍后您执行AJAX调用,例如ResultsAsync_Read,则更改ViewBag 会因页面已呈现而无效。您可以做的唯一修改页面的方法是返回一些JSON,并根据AJAX回调中的JSON结果更改DOM (即使用jQuery / javascript)。