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

asp.net mvc 3 - MVC binding to model with list property ignores other properties

I have a basic ViewModel with a property that is a List of complex types. When binding, I seem to be stuck with getting either the list of values, OR the other model properties depending on the posted values (i.e. the view arrangement).

The view model:

public class MyViewModel
{
    public int Id { get; set; }
    public string Property1 { get; set; }
    public string Property2 { get; set; }

    public List<MyDataItem> Data { get; set; }
}

public class MyDataItem
{
    public int Id { get; set; }
    public int ParentId { get; set; }
    public string Name { get; set; }
    public string Value { get; set; }
}

The controller actions:

    public ActionResult MyForm()
    {
        MyViewModel model = new MyViewModel();

        model.Id = 1;
        model.Data = new List<MyDataItem>() 
        { 
            new MyDataItem{ Id = 1, ParentId = 1, Name = "MyListItem1", Value = "SomeValue"}
        }; 

        return View(model);
    }

    [HttpPost]
    public ActionResult MyForm(MyViewModel model)
    {
        //...

        return View(model);
    }

Here is the basic view (without the list mark-up)

@using (Html.BeginForm()) {
    @Html.ValidationSummary(true)
    <fieldset>
        <legend>My View Model</legend>

        @Html.HiddenFor(model => model.Id)

        <div class="editor-label">
            @Html.LabelFor(model => model.Property1)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Property1)
            @Html.ValidationMessageFor(model => model.Property1)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.Property2)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Property2)
            @Html.ValidationMessageFor(model => model.Property2)
        </div>

        <p>
            <input type="submit" value="Save" />
        </p>
    </fieldset>
}

When posted back to the controller, I get the 2 property values and a null value for the 'Data' property as expected.

Without List Mark-up

If I add the mark-up for the List as follows (based on the information in this Scott Hanselman post and Phil Haack's post):

<div class="editor-field">
@for (int i = 0; i < Model.Data.Count(); i++)
{
    MyDataItem data = Model.Data[i];
    @Html.Hidden("model.Data[" + i + "].Id", data.Id)
    @Html.Hidden("model.Data[" + i + "].ParentId", data.ParentId)
    @Html.Hidden("model.Data[" + i + "].Name", data.Name)
    @Html.TextBox("model.Data[" + i + "].Value", data.Value)
}
</div>

The 'Data' property of the model is successfully bound but the other properties are null.

With List Mark-up

The form values posted are as follows:

Id=1&Property1=test1&Property2=test2&model.Data%5B0%5D.Id=1&model.Data%5B0%5D.ParentId=1&model.Data%5B0%5D.Name=MyListItem1&model.Data%5B0%5D.Value=SomeValue

Is there a way to get both sets of properties populated or am I just missing something obvious?

EDIT:

For those of you who are curious. Based on the answer from MartinHN, the original generated mark-up was:

<div class="editor-field">
    <input id="model_Data_0__Id" name="model.Data[0].Id" type="hidden" value="1" />
    <input id="model_Data_0__ParentId" name="model.Data[0].ParentId" type="hidden" value="1" />
    <input id="model_Data_0__Name" name="model.Data[0].Name" type="hidden" value="MyListItem1" />
    <input id="model_Data_0__Value" name="model.Data[0].Value" type="text" value="SomeValue" />        
</div>

The new generated mark-up is:

<div class="editor-field">
    <input id="Data_0__Id" data-val="true" name="Data[0].Id" type="hidden" value="1" data-val-number="The field Id must be a number." data-val-required="The Id field is required." />
    <input id="Data_0__ParentId" name="Data[0].ParentId" type="hidden" value="1"  data-val="true" data-val-number="The field ParentId must be a number." data-val-required="The ParentId field is required." />
    <input id="Data_0__Name" name="Data[0].Name" type="hidden" value="MyListItem1" />
    <input id="Data_0__Value" name="Data[0].Value" type="text" value="SomeValue" />        
</div>

Which results in the following posted values:

Id=1&Property1=test1&Property2=test2&Data%5B0%5D.Id=1&Data%5B0%5D.ParentId=1&Data%5B0%5D.Name=MyListItem1&Data%5B0%5D.Value=SomeValue

Notice there's no 'model.' in the name and posted values...

See Question&Answers more detail:os

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

1 Reply

0 votes
by (71.8m points)

Try to change the code for the Data collection to this, and let MVC take care of the naming:

<div class="editor-field">
@for (int i = 0; i < Model.Data.Count(); i++)
{
    @Html.HiddenFor(m => m.Data[i].Id)
    @Html.HiddenFor(m => m.Data[i].ParentId)
    @Html.HiddenFor(m => m.Data[i].Name)
    @Html.TextBoxFor(m => m.Data[i].Value)
}
</div>

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

...