MVC3 - Viewmodel with list of complex types

后端 未结 2 590
南旧
南旧 2020-12-08 08:51

Apologies if this has been asked before; there are a million ways to phrase it so searching for an answer has proved difficult.

I have a viewmodel with the following

相关标签:
2条回答
  • 2020-12-08 09:13

    My assumption is that this is happening because even though I'm editing its contents, the Devices property is never explicitly included in the form.

    No, your assumption is wrong. The reason this doesn't get bound properly is because your input fields doesn't have correct names. For example they are called name="IsSelected" instead of name="Devices[0].IsSelected". Take a look at the correct wire format that needs to be used to bind to collections: http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx

    But why this happens?

    It happens because of the foreach loop that you used in your view. You used x => device.IsSelected as lambda expression for the checkbox but this doesn't take into account the Devices property at all (as you can see by looking at the generated source code of your web page).

    So what should I do?

    Personally I would recommend you using editor templates as they respect the navigational context of complex properties and generate correct input names. So get rid of the entire foreach loop in your view and replace it with a single line of code:

    @Html.EditorFor(x => x.Devices)
    

    and now define a custom editor template that will automatically be rendered by ASP.NET MVC for each element of the Devices collection. Warning: the location and name of this template are very important as this works by convention: ~/Views/Shared/EditorTemplates/SelectableDeviceViewModel.cshtml:

    @model SelectableDeviceViewModel
    @Html.HiddenFor(x => x.DeviceInstanceId)
    <tr>
        <td>@Html.CheckBoxFor(x => x.IsSelected)</td>
        <td>@Html.DisplayFor(x => x.Name)</td>
    </tr>
    

    Another approach (which I don't recommend) is to change your current ICollection in your view model to an indexed collection (such as an IList<T> or an array T[]):

    public class AssignSoftwareLicenseViewModel
    {
        public int LicenseId { get; set; }
        public IList<SelectableDeviceViewModel> Devices { get; set; }
    }
    

    and then instead of the foreach use a for loop:

    @for (var i = 0; i < Model.Devices.Count; i++)
    {
        @Html.HiddenFor(x => x.Devices[i].DeviceInstanceId)
        <tr>
            <td>@Html.CheckBoxFor(x => x.Devices[i].IsSelected)</td>
            <td>@Html.DisplayFor(x => x.Devices[i].Name</td>
        </tr>
    }
    
    0 讨论(0)
  • 2020-12-08 09:17

    EditorFor templates work and keep the code clean. You don't need the loops and the model is posted back correctly.

    However, has anyone had problems with validation on complex viewmodels (nested EditorFor templates)? I'm using Kendo Validator and am running into all sorts of jquery errors.

    0 讨论(0)
提交回复
热议问题