Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
743 views
in Technique[技术] by (71.8m points)

vb.net - Updating a list of objects in mvc4

I have taken an issue that I am having with a asp.net mvc4 applications and simplified it so I can post it here. My basic problem is that I am trying to send a list of items to my view and edit the check box of any of the items and then send the list items back to the controller and be able to eventually save to the database. The way the code is written right now when I send the list back to the controller it comes across as a null value just like it was never instantiated.

The code is as follows:

Public Class Person
    Property ID As Integer
    Property Name As String
    Property Active As Boolean
End Class

In the controller I call a class called BuildPeople that is really just a way to build the the list to pass around:

Public Class BuildPeople

    Public Function GetPersonList() As List(Of Person)
        Dim personList As New List(Of Person)
        personList.Add(GetPerson(1, "Chris", True))
        personList.Add(GetPerson(2, "Ken", True))
        personList.Add(GetPerson(3, "Jen", True))
        Return personList
    End Function

    Private Function GetPerson(id As Integer, name As String, active As Boolean) As Person
        Dim p As New Person
        p.ID = id
        p.Name = name
        p.Active = active
        Return p
    End Function  
End Class

The controller only has the edit ability:

    Imports System.Web.Mvc

Public Class PeopleController
    Inherits Controller

    ' GET: /People
    Function Index() As ActionResult
        Return View()
    End Function

    ' GET: /People/Edit/5
    Function Edit() As ActionResult
        Dim bp As New BuildPeople
        Dim model As New List(Of Person)
        model = bp.GetPersonList
        ViewData.Model = model
        Return View()
    End Function

    ' POST: /People/Edit/5
    <HttpPost()>
    Function Edit(ByVal listPeople As List(Of Person)) As ActionResult
        Try
            ' TODO: Add update logic here
            If listPeople Is Nothing Then
                'Don't want to end up here
                Return View()
            Else
                'Want to end up here
                Dim i As Integer = listPeople.Count
                Return View()
            End If
        Catch
            Return View()
        End Try
    End Function
End Class

And then the view is as follows:

@ModelType List(Of Person)
@Code
    ViewData("Title") = "Edit"
    Layout = "~/Views/Shared/_Layout.vbhtml"
End Code

<h2>Edit</h2>

@Using (Html.BeginForm())
    @Html.AntiForgeryToken()

    @<div class="form-horizontal">
        <h4>Person</h4>
        <hr />
        @For Each item In Model
        Dim currentitem = item
            @Html.HiddenFor(Function(model) currentitem.ID)
            @Html.EditorFor(Function(model) currentitem.Name)
            @Html.EditorFor(Function(model) currentitem.Active)
        Next

        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Save" class="btn btn-default" />
            </div>
        </div>
    </div>
End Using

<div>
    @Html.ActionLink("Back to List", "Index")
</div>
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

So you have to have some understanding of how HTML forms work as well as how the MVC model binder works.

Checkboxes only send a value back in the post data if they are checked.

Next, the model binder in MVC will reconstitute collection/list objects as long as the field naming follows the proper naming convention.

So your loop For Each item In Model needs to produce items with the correct name.

Let's change your model slightly.

Public Class PeopleModel
  Public Property People As List(Of Person)
  Public Property SelectedPeople As List(Of Int64)  ' Assuming Person.ID is Int64
End Class

Then your change your view's loop like so:

Dim itemIndex As Int32 = 0
For Each person As Person In Model.People
  @<input type='checkbox' name='SelectedPeople[@itemIndex]' id='person_@person.ID' value='@person.ID' />
  @<input type='hidden' name='SelectedPeople[@itemIndex]' value='-1' />
  itemIndex += 1
Next

We place the hidden element in there because it will provide a field value for unchecked items. Otherwise the first unchecked item would break the indices and the model binder would stop.

Now in your controller's post handler:

<HttpPost>
Public Function ActionName(model As PeopleModel) As ActionResult

  For Each id As Int64 In model.SelectedPeople
    If 0 < id Then
      ' This is the id of a selected person - do something with it.
    End If
  Next

End Function

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...