Kendo Grid基于对象数组的多列组 [英] Kendo Grid multi column group based on object array

查看:209
本文介绍了Kendo Grid基于对象数组的多列组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am relatively new to MVC (and Kendo) but I have managed to setup a grid which contains multi column headers using the columns.Group functionality.

@(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设置并传递的数组动态构建列.

As you can see I am trying to build the columns dynamically based on an array which has been setup and passed using ViewBag.

控制器异步函数,该函数设置ViewBag.Lots从顶级IEnumerable<Result>对象提取数组:

Controller async function which sets up ViewBag.Lots extracting the array from the top level IEnumerable<Result> object:

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));
        }

运行此命令时,尝试访问foreach中的ViewBag.Lots属性时收到以下错误.

When I run this, I get the following error when trying to access the ViewBag.Lots attribute in the foreach.

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

NullReferenceException: Object reference not set to an instance of an object.

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

Does someone know why I am getting this error and also if there is a more efficient way to achieve my goal?

我不是使用ViewBag来保存Lot对象的列表,而是使用它来保存整个List<Result>中可用的最大手数. 我已经在船上接受@ ken2k的建议,并在Controller的Index()功能内完成了此操作:

Instead of using the ViewBag to hold the list of Lot objects, I am using it to hold the maximum number of lots available in the entire List<Result>s. I have taken @ken2k's advice onboard and done this within the Index() function of the Controller:

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");
        }

然后,我遍历可用的最大手数并创建所需的列:

Then I loop over the maximum number of lots available and create the columns required:

.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(); });
                })

这将导致网格显示如下:

This results in a grid displaying like so:

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

So I have managed to create the number of multi-header columns required to display the data. However, I am now getting an error:

未捕获的TypeError:无法读取未定义的属性"Result"

Uncaught TypeError: Cannot read property 'Result' of undefined

推荐答案

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

Your ResultsAsync_Read method is an async method that will be called by the Kendo framework from a javascript AJAX call, i.e. after your page has been loaded and rendered.

这意味着呈现页面时ViewBag.Lots实际上为空,这会引发异常.

This means that when your page is rendered, ViewBag.Lots is actually null, which throw the exception.

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

What you need is to initialize this value when you load the page, not inside your ResultsAsync_Read method. Basically:

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东西实际上是如何工作的.基本上,这些步骤是:

It's important to remember how the MVC stuff actually works. Basically the steps are:

  • 服务器在.../索引路由上收到请求
  • 服务器执行Index()操作
  • 当操作返回this.View()(与this.View("Index")等效)时,它将呈现Index.cshtml剃刀视图(这意味着ViewBag在此处不能为空)
  • 如果以后再执行诸如ResultsAsync_Read之类的AJAX调用,则更改ViewBag 不会生效,因为页面已呈现.您唯一可以做的就是修改页面,返回一些JSON,并根据JSON结果从AJAX回调内部更改DOM (即使用jQuery/javascript).
  • the server receives a request on the .../Index route
  • the server executes the Index() action
  • as the action returns this.View() (which would be equivalent to this.View("Index")), it renders the Index.cshtml razor view (that means the ViewBag must be not null here)
  • if later you do AJAX calls such as ResultsAsync_Read, changing the ViewBag won't have any effect as the page is already rendered. The only thing you could do to modify your page, is to return some JSON, and change the DOM based on the JSON result from inside your AJAX callback (i.e. using jQuery/javascript).

这篇关于Kendo Grid基于对象数组的多列组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆