MVC model binding to edit a list not working

2019-08-05 08:23发布

问题:

I can't figure out why this won't work. Everything I've read (both here and across the web) says this is how to bind to a list for editing but I'm not having any success. I have two problems:

  1. The HTML form elements emitted by the view are not being indexed (each one is named "Qty" and "BoxID" instead of "[0].Qty" and "[0].BoxID"). Everything I've read on this subjuct says the HTML.EditorFor and HiddenFor helpers should pick this up automatically.

  2. Even when I manually change the view to spit out the correct HTML (form elements with the right names) model binding isn't happening correctly and the collection parameter in the controller action method is null.

Any ideas? Am I doing something wrong?

Here's the view:

@ModelType IEnumerable(of HonorBox)
@Code
ViewData("Title") = "Index"
End Code

<h2>Index</h2>

@Html.BeginForm("Index", "HonorBoxes")
@Html.AntiForgeryToken()


@For x = 0 To Model.Count - 1
    @<tr>
         <td>
             @Html.DisplayFor(Function(i) Model(x).BoxID)
             @Html.HiddenFor(Function(i) Model(x).BoxID)
         </td>
         <td>
             @Html.TextBoxFor(Function(i) Model(x).Qty)
             @Html.ValidationMessageFor(Function(i) Model(x).Qty)
         </td>
    </tr>
Next

And these are the controller methods:

    Function Index() As ActionResult
        Dim hb = From h In db.honorBoxes Select h Where Not h.Filled And Not h.Hold
        Return View(hb.ToList())
    End Function

    <HttpPost>
    Function Index(boxes As IEnumerable(Of HonorBox)) As ActionResult
        If ModelState.IsValid Then
            For Each box In boxes
                Dim cbox = db.honorBoxes.Find(box.BoxID)
                If Not IsDBNull(box.Qty) AndAlso cbox.Qty <> box.Qty Then
                    cbox.Qty = box.Qty
                    cbox.Filled = True
                End If
            Next
            db.SaveChanges()
        End If
        Return RedirectToAction("Index")
    End Function

Finally here's the model

Public Class HonorBox
    <Key> Public Property BoxID As Integer
    Public Property AssetID As Nullable(Of Integer)
    Public Property Asset As Asset
    Public Property BoxType As String
    Public Property Hold As Nullable(Of Boolean)
    Public Property Filled As Nullable(Of Boolean)
    Public Property Qty As Nullable(Of Integer)
End Class

回答1:

In order for the model binder to pick it up the model type needs to be of type List not IEnumerable.

Changing it to this will work:

@ModelType List(of HonorBox)