在ASP.NET MVC中使用Kendo MultiSelect和Kendo UI Grid

时间:2022-09-12 09:09:16

This is related to another question I asked about recently. I'm trying to bind user role information to a grid, and I'm assigning roles to a user. Each user can be in multiple roles within the database, and these should be edited using a Kendo UI MultiSelect.

这与我最近提出的另一个问题有关。我正在尝试将用户角色信息绑定到网格,我正在为用户分配角色。每个用户可以在数据库中担任多个角色,这些角色应使用Kendo UI MultiSelect进行编辑。

When I select the roles required and post back to the controller, the array of "RoleBasicModel" objects contains the required number of roles, but all their properties are empty.

当我选择所需的角色并回发给控制器时,“RoleBasicModel”对象数组包含所需数量的角色,但它们的所有属性都是空的。

The models are defined as:

模型定义为:

public class UserInfo
{
    public string UserId { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string UserName { get; set; }
    public string Roles { get; set; }
    public IEnumerable<RoleBasicModel> RoleList { get; set; }
}
public class RoleBasicModel
{
    public string Id { get; set; }
    public string Text { get; set; }
}

The grid is setup as:

网格设置为:

    @(Html.Kendo().Grid<Models.UserInfo>()
    .Name("userGrid")
    .Columns(columns =>
    {
        columns.Bound(p => p.UserName);
        columns.Bound(p => p.FirstName);
        columns.Bound(p => p.LastName);
        columns.Bound(p => p.Roles).EditorTemplateName("RoleListEditor").Template(p => p.RoleList);
        columns.Command(command => { command.Edit(); command.Destroy(); });
    })
    .Filterable()
    .Sortable()
    .Resizable(r => r.Columns(true))
    .Editable(editable => { editable.Mode(GridEditMode.InLine); editable.DisplayDeleteConfirmation("Are you sure you want to remove this user?"); })
    .HtmlAttributes(new { style = "min-height:90px;max-height:450px;" })
    .DataSource(dataSource => dataSource
        .Ajax()
        .Events(events => events.Error("error_handler"))
        .Model(model =>
        {
            model.Id(p => p.UserId);
            model.Field(p => p.UserId).Editable(false);
            model.Field(p => p.FirstName).Editable(true);
            model.Field(p => p.LastName).Editable(true);
            model.Field(p => p.UserName).Editable(false);
            model.Field(p => p.RoleList).Editable(true);
        }
        ).Read(read => read.Action("GetAllUsers", "Admin").Type(HttpVerbs.Get))
        .Update(update => update.Action("UpdateUser", "Admin").Type(HttpVerbs.Post))
        .Destroy(update => update.Action("DeleteUser", "Admin").Type(HttpVerbs.Post))
    )
)

And my editor template, which uses the Kendo MultiSelect, is defined as:

我的编辑器模板使用了Kendo MultiSelect,定义如下:

@Html.Kendo().MultiSelect().Name("RoleList").DataTextField("Text").DataValueField("Id").BindTo((IEnumerable<Models.RoleBasicModel>)ViewData["uroles"]).Placeholder("No role selected")

Is there any obvious reason why the data sent back to the server is empty? I'm suspecting I'm missing something from the MultiSelect control that'll define the correct model to use. I have referred to the test project that is often cited as an answer to similar questions, but I've had no joy with that either.

发送回服务器的数据是否为空是否有明显的原因?我怀疑我错过了MultiSelect控件中的某些内容,它将定义要使用的正确模型。我已经提到过经常被引用作为类似问题的答案的测试项目,但我对此也没有任何喜悦。

As requested, (an abridged version of) the controller I'm using:

根据要求,(正在删除的版本)我正在使用的控制器:

 public ActionResult ManageUsers()
    {            
        PopulateRoles();
        return View();
    }

    private void PopulateRoles()
    {
        ViewData["uroles"] = new ApplicationDbContext().Roles.Select(r => new RoleBasicModel { Text = r.Name, Id = r.Id }).ToList();
    }

    [AcceptVerbs(HttpVerbs.Get)]
    public ActionResult GetAllUsers([DataSourceRequest]DataSourceRequest request)
    {
        using (var context = new ApplicationDbContext())
        {
            var allUsers = context.Users.ToList().Select(x =>
                new UserInfo
                {
                    UserName = x.UserName,
                    UserId = x.Id,
                    FirstName = x.FirstName,
                    LastName = x.LastName,
                    RoleList = x.Roles.Select(p => new RoleBasicModel { Text = p.Role.Name, Id = p.RoleId }),
                    Roles = string.Join(", ", x.Roles.Select(p => p.Role.Name).ToList())
                }).ToList();
            return Json(allUsers.ToDataSourceResult(request), JsonRequestBehavior.AllowGet);
        }
    }

    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult UpdateUser([DataSourceRequest] DataSourceRequest request, UserInfo user)
    {
        if (user != null && ModelState.IsValid)
        {
            using (var context = new ApplicationDbContext())
            {
// Do something with the user details
            }
        }

        return Json(new[] { user }.ToDataSourceResult(request, ModelState));
    }

EDIT: Upon viewing the data posted back to the server, it appears as if the array of selected objects isn't parsed correctly. The format should be RoleList[0].Id:123456 but is instead RoleList[0][Id]:123456. I'm thinking this could be a problem with the MultiSelect control, rather than any code I've written?

编辑:在查看发回服务器的数据时,看起来好像未正确解析所选对象的数组。格式应为RoleList [0] .Id:123456,而是RoleList [0] [Id]:123456。我认为这可能是MultiSelect控件的问题,而不是我编写的任何代码?

1 个解决方案

#1


4  

So I've eventually worked out what the problem was. As per my edit, I noticed that the data wasn't serialised properly from the MultiSelect control.

所以我最终解决了问题所在。根据我的编辑,我注意到数据没有从MultiSelect控件正确序列化。

I spent some time getting the example available on the Kendo website working and I noticed that they posted the data serialised correctly and incorrectly to the server. The trick they used (which seems ridiculous to me) is that on the Update function on the grid, they serialise any data inside an array for themselves i.e.

我花了一些时间在剑道网站上获得示例,我注意到他们将数据序列化正确且错误地发布到服务器上。他们使用的技巧(这对我来说似乎很荒谬)是在网格上的Update函数中,他们为自己序列化数组内的任何数据,即

.Update(update => update.Action("UpdateUser", "Admin").Type(HttpVerbs.Post).Data("serialize"))

.Update(update => update.Action(“UpdateUser”,“Admin”)。Type(HttpVerbs.Post).Data(“serialize”))

Where the "serialize" function is defined as:

“serialize”函数定义为:

function serialize(data) {
    for (var property in data) {
        if ($.isArray(data[property])) {
            serializeArray(property, data[property], data);
        }
    }
}

function serializeArray(prefix, array, result) {
    for (var i = 0; i < array.length; i++) {
        if ($.isPlainObject(array[i])) {
            for (var property in array[i]) {
                result[prefix + "[" + i + "]." + property] = array[i][property];
            }
        }
        else {
            result[prefix + "[" + i + "]"] = array[i];
        }
    }
}

Having searched around extensively for a resolution to my problem, and other people have been pointed to a working solution without explanation, I thought it might be useful to someone else to understand what the problem is when you try to use a Kendo MultiSelect in a Kendo Grid, rather than just saying "look at this example".

我已经广泛搜索了我的问题的解决方案,并且其他人已经指出了一个没有解释的工作解决方案,我认为当你尝试在Kendo中使用Kendo MultiSelect时,其他人可能有用了解问题是什么。网格,而不仅仅是说“看看这个例子”。

tl;dr Always serialise the data inside a Kendo MultiSelect yourself before posting to the server (if you're using a Kendo Grid)

tl; dr总是在发布到服务器之前自己序列化Kendo MultiSelect内的数据(如果你使用的是Kendo Grid)

#1


4  

So I've eventually worked out what the problem was. As per my edit, I noticed that the data wasn't serialised properly from the MultiSelect control.

所以我最终解决了问题所在。根据我的编辑,我注意到数据没有从MultiSelect控件正确序列化。

I spent some time getting the example available on the Kendo website working and I noticed that they posted the data serialised correctly and incorrectly to the server. The trick they used (which seems ridiculous to me) is that on the Update function on the grid, they serialise any data inside an array for themselves i.e.

我花了一些时间在剑道网站上获得示例,我注意到他们将数据序列化正确且错误地发布到服务器上。他们使用的技巧(这对我来说似乎很荒谬)是在网格上的Update函数中,他们为自己序列化数组内的任何数据,即

.Update(update => update.Action("UpdateUser", "Admin").Type(HttpVerbs.Post).Data("serialize"))

.Update(update => update.Action(“UpdateUser”,“Admin”)。Type(HttpVerbs.Post).Data(“serialize”))

Where the "serialize" function is defined as:

“serialize”函数定义为:

function serialize(data) {
    for (var property in data) {
        if ($.isArray(data[property])) {
            serializeArray(property, data[property], data);
        }
    }
}

function serializeArray(prefix, array, result) {
    for (var i = 0; i < array.length; i++) {
        if ($.isPlainObject(array[i])) {
            for (var property in array[i]) {
                result[prefix + "[" + i + "]." + property] = array[i][property];
            }
        }
        else {
            result[prefix + "[" + i + "]"] = array[i];
        }
    }
}

Having searched around extensively for a resolution to my problem, and other people have been pointed to a working solution without explanation, I thought it might be useful to someone else to understand what the problem is when you try to use a Kendo MultiSelect in a Kendo Grid, rather than just saying "look at this example".

我已经广泛搜索了我的问题的解决方案,并且其他人已经指出了一个没有解释的工作解决方案,我认为当你尝试在Kendo中使用Kendo MultiSelect时,其他人可能有用了解问题是什么。网格,而不仅仅是说“看看这个例子”。

tl;dr Always serialise the data inside a Kendo MultiSelect yourself before posting to the server (if you're using a Kendo Grid)

tl; dr总是在发布到服务器之前自己序列化Kendo MultiSelect内的数据(如果你使用的是Kendo Grid)