Подтвердить что ты не робот

Связывание MVC с моделью со свойством list игнорирует другие свойства

У меня есть базовый ViewModel со свойством, которое является списком сложных типов. При привязке я, кажется, застрял в получении либо списка значений, либо других свойств модели в зависимости от опубликованных значений (т.е. Схемы представления).

Модель просмотра:

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; }
}

Действия контроллера:

    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);
    }

Вот основной вид (без разметки списка)

@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>
}

Когда отправляется обратно на контроллер, я получаю значения свойств 2 и нулевое значение для свойства Data, как и ожидалось.

Without List Mark-up

Если я добавлю надпись для списка следующим образом (на основе информации в этом сообщение Scott Hanselman и Фил Хаак пост):

<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>

Свойство "Данные" модели успешно связано, а остальные свойства - null.

With List Mark-up

Выводимые значения форм:

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

Есть ли способ получить оба набора свойств, заполненных или я просто пропущу что-то очевидное?

EDIT:

Для тех из вас, кто любопытен. Исходя из ответа MartinHN, оригинальная сгенерированная надбавка была:

<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>

Новая сгенерированная надбавка:

<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>

Это приводит к следующим опубликованным значениям:

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

Обратите внимание, что нет "модели". в имени и размещенных значениях...

4b9b3361

Ответ 1

Попробуйте изменить код для коллекции данных на это, и пусть MVC позаботится об именовании:

<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>

Ответ 2

В качестве альтернативы вы могли бы создать EditorTemplate для вашей вложенной ViewModel следующим образом.

@model MyDataItem
@Html.HiddenFor(model => model.Id)
@Html.HiddenFor(model => model.ParentId)
@Html.HiddenFor(model => model.Name)
@Html.TextBoxFor(model => model.Value)

Создайте папку с именем "EditorTemplates" в вашей общей папке и сохраните ее как "MyDataItem.cshtml".

Затем в вашем представлении просто вызовите следующее вместо цикла foreach:

@Html.EditorFor(model => model.Data)

Чувствует себя немного менее хакерским ИМО:)

Ответ 3

Только мои 2 цента, но что-то стоит отметить с этой проблемой - член данных в модели просмотра должен быть определен как общедоступное свойство для привязки модели обратной связи для работы. У меня была очень похожая проблема с вышеизложенным, но я использовал публичный элемент данных в моей модели просмотра. Тот же HTML генерируется, как показано выше, и все выглядит хорошо, но модельное связующее отбросило пустую коллекцию. Стоит наблюдать за...