Asp.net mvc 基于对象数组的剑道网格多列组

Asp.net mvc 基于对象数组的剑道网格多列组,asp.net-mvc,razor,kendo-grid,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");

我对
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")
             )
        )
运行此操作时,在尝试访问
foreach
中的
ViewBag.Lots
属性时,出现以下错误

NullReferenceException:对象引用未设置为 反对

有人知道我为什么会犯这样的错误吗?有没有更有效的方法来实现我的目标

编辑: 我不是使用ViewBag来保存
批次
对象列表,而是使用它来保存整个
列表
中可用的最大批次数。 我在船上听取了@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");
        }
公共异步任务索引()
{
QCTest test=新型号.Acusera.QCTest();
test.TestID=3;
IEnumerable controlset=wait_manager.ReadAsync(测试);
ViewBag.MaxLots=controlSets.Max(x=>x.LotResults.Count);
返回视图(“~/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(); });
                })
.Columns(Columns=>
{
columns.Bound(c=>c.ResultDateTime).Title(“日期时间”);
对于(int i=0;iGroup
.标题(“测试”)
.列(信息=>
{
绑定(x=>x.LotResults[i].Result.Count);
info.Bound(x=>x.LotResults[i].Result.Mean);
绑定(x=>x.LotResults[i].Result.SD);
}));
}
columns.Bound(c=>c.StandardComment.Description).Title(“Comment”);
columns.Bound(c=>c.ReviewComment.Description).Title(“审阅注释”);
Command(Command=>{Command.Destroy();});
})
这将导致网格显示如下所示:

因此,我成功地创建了显示数据所需的多标题列的数量。但是,我现在得到一个错误:

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


您的
ResultsAsync\u Read
方法是一种异步方法,Kendo框架将通过javascript AJAX调用调用该方法,即在加载和呈现页面后调用该方法

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

您需要的是在加载页面时初始化该值,而不是在
ResultsAsync\u 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();
}
公共异步任务索引()
{
//在呈现视图之前获取值
IEnumerable controlset=wait_manager.ReadAsync(测试);
//ViewBag属性将从Razor视图中可用
ViewBag.Lots=controlset.Select(x=>x.LotResults);
//返回显示网格的视图
返回这个.View();
}
记住MVC是如何工作的是很重要的。基本上,这些步骤是:

  • 服务器通过…/索引路由接收请求
  • 服务器执行Index()操作
  • 当操作返回this.View()(相当于this.View(“Index”))时,它将呈现Index.cshtml razor视图(这意味着ViewBag在此不能为null)
  • 如果以后执行AJAX调用,例如
    ResultsAsync\u Read
    ,更改ViewBag不会有任何效果,因为页面已经呈现了。修改页面的唯一方法是返回一些JSON,并基于AJAX回调内部的JSON结果更改DOM(即使用jQuery/javascript)

谢谢您在ken2k提供的信息。我感谢你的答复。稍后肯定需要执行此操作(以便根据不同的用户选择重新绑定网格)。因此,有没有一种方法可以通过razor grid view设置直接使用
Lot
数组对象?@Sandman不太明白,页面加载后是否需要动态更改列(我是说使用AJAX)?是的,当用户做出不同的
测试
选择时,需要从数据库中检索新值。
Lot[]
长度可以从1到6不等,因此这意味着我需要根据所选的
test
创建1到6列。@Sandman这样就更容易重新加载整个视图(因此1/您在索引操作2中填充了ViewBag/页面再次呈现新列)。如果您需要动态更改列(即通过AJAX而不重新加载整个页面),那么实现起来会有点困难。好的,我已经根据我对代码所做的一些编辑更新了我的问题。我现在使用
ViewBag
来保存整个
列表中可用的
Lot
对象的最大数量,但遇到了另一个障碍。你有什么想法吗?提前谢谢
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();
}