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
424 views
in Technique[技术] by (71.8m points)

asp.net - ViewModel's list is null in action

I'm working on my first ASP.NET MVC 3 application and I've got a View that looks like this:

@model IceCream.ViewModels.Note.NotesViewModel
@using (Html.BeginForm())
{
    @Html.ValidationSummary(true)
    @Html.TextBoxFor(m => m.Name)

    foreach (var item in Model.Notes)
    {
        @Html.EditorFor(m => item);
    }

    <input type="submit" value="Submit"/>
}

And I have an EditorTemplate that looks like this:

@model IceCream.ViewModels.Note.NoteViewModel
<div>
    @Html.HiddenFor(m => m.NoteID)
    @Html.TextBoxFor(m => m.NoteText)
    @Html.CheckBoxFor(m => m.IsChecked)
</div>

NotesViewModel looks like so:

    public class NotesViewModel
    {
        public string Name { get; set; }
        public IEnumerable<NoteViewModel> Notes { get; set; }
    }

NoteViewModel looks like this:

public class NoteViewModel
{
    public int NoteID { get; set; }
    public System.DateTime Timestamp { get; set; }
    public string NoteText { get; set; }
    public bool IsChecked { get; set; }
}

The NotesViewModel is populated just fine when it is passed to the view. However when the submit button is clicked, the controller action handling the post has only the value for the Name property of the viewmodel. The Notes property - the list of notes that have been checked/unchecked by the user - is null. I've got a disconnect between the populating of those TextBoxFor and CheckBoxFor elements when the view is displayed and the ViewModel being sent back. Guidance on this?


SOLUTION Thanks go to Mystere Man for setting me straight on this. As I understand it, essentially by changing my loop to

@Html.EditorFor(m => m.Notes)

changes the underlying HTML, which I understand provides for the proper model binding on the post. Looking at the resulting HTML, I see that I get the following generated for one of the Notes:

<div>
  <input id="Notes_0__NoteId" type="hidden" value="1" name="Notes[0].NoteId">
  <input id="Notes_0__NoteText" type="text" value="Texture of dessert was good." name="Notes[0].NoteText">
  <input id="Notes_0__IsChecked" type="checkbox" value="true" name="Notes[0].IsChecked>
</div>

Which is different than this HTML generated by my original code:

<div>
   <input id="item_NoteId" type="hidden" value="1" name="item.NoteId>
   <input id="item_NoteText" type="text" value="Texture of dessert was good." name="item.NoteText" >
   <input id="item_IsChecked" type="checkbox" value="true" name="item.IsChecked">
</div>

By looping through the Notes, the generated HTML essentially loses any references to the viewmodel's Notes property and while the HTML gets populated correctly, the setting of the checkbox values has no way to communicate their values back to the viewmodel, which I guess is the point of the model binding.

So I learned something, which is good.

See Question&Answers more detail:os

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

1 Reply

0 votes
by (71.8m points)

You're a smart guy, so look at your view. Then, consider how the HTML gets generated. Then, consider how on postback the Model Binder is supposed to know to re-populate Notes based on the generated HTML.

I think you'll find that your HTML doesn't have enough information in it for the Model Binder to figure it out.

Consider this:

@EditorFor(m => Model.Notes)

Rather than the for loop where you are basically hiding the context from the EditorFor function.


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

...