Связывание Asp.Net MVC. Получить список <Model>на контроллере - PullRequest
2 голосов
/ 01 июня 2011

У меня есть вид:

    @using (Html.BeginForm("ProcessRoute", "Calculator"))
    {

            @Html.TextBox("CityArrival", null, new { @style = "width: 300px;" })
            @Html.TextBox("CityDeparture", null, new { @style = "width: 300px;" })
            @{ Html.RenderPartial("BusModelList", @Model.BusModels);  }      
            <input id="submit" type="submit" value="Поиск" />
    }

частичный вид:

@model List<ViewModels.GroupedBusModelsSelectable>
<table>
    @foreach (var item in Model)
    {
        <tr>
            <td colspan="3" align="left">@item.BusType.Name</td>
        </tr>
       foreach (var bus in item.BusModels.OrderBy(c => c.Bus.NumPlaces).ToList())
       {
            @Html.EditorFor(x=>bus);
       }
    }
</table>

и редактор:

@model ViewModels.BusModelSelectable
<tr>
    <td>
        @Html.HiddenFor(x => x.Bus.Id)
        @Html.HiddenFor(x => x.Bus.FullName)
        @Html.CheckBoxFor(x => x.IsSelected)
    </td>
    <td>
        <img>
    <td>
        @Model.Bus.FullName
    </td>
</tr>

Теперь я хотел бы получить все busModels (с выбранными) на контроллере:

   [HttpPost]
   public ActionResult ProcessRoute(string CityArrival, string CityDeparture, IEnumerable<GroupedBusModelsSelectable> BusModels)

По какой-то причине BusModels имеет значение null

В HttpContext.Request.Form

Я вижу список (bus.IsSlected, bus.Bus.Id). Как я могу получить его на контроллере?

1020 * РЕШЕНИЕ *

После совета Ника Ларсена я понимаю, что я должен был проиндексировать имена в своем HTML. Поскольку у меня есть двухуровневая коллекция, я должен сделать это дважды.

PartialView:

@model List<Avtobus66.ViewModels.GroupedBusModelsSelectable>
<table>
        @for (int j = 0; j < Model.Count(); j++)
        {
            <tr>
                <td colspan="3" align="left">@Model[j].BusType.Name</td>
            </tr>
            for (int i = 0; i < Model[j].BusModels.Count(); i++)
            {
               @Html.EditorFor(x => Model[j].BusModels[i]);
            }
        }
</table>

Давайте посмотрим html сейчас:

<input name="[0].BusModels[0].Bus.Id" type="hidden" value="1" />
<input name="[0].BusModels[0].IsSelected" type="checkbox" value="true" />
<input name="[0].BusModels[0].IsSelected" type="hidden" value="false" />

<input name="[0].BusModels[1].Bus.Id" type="hidden" value="2" />
<input name="[0].BusModels[1].IsSelected" type="checkbox" value="true" />
<input name="[0].BusModels[1].IsSelected" type="hidden" value="false" />

<input name="[0].BusModels[2].Bus.Id" type="hidden" value="3" />
<input name="[0].BusModels[2].IsSelected" type="checkbox" value="true" />
<input name="[0].BusModels[2].IsSelected" type="hidden" value="false" />

<input name="[1].BusModels[0].Bus.Id" type="hidden" value="4" />
<input name="[1].BusModels[0].IsSelected" type="checkbox" value="true" />
<input name="[1].BusModels[0].IsSelected" type="hidden" value="false" />

На контроллере я готов получить 2-уровневую коллекцию сейчас. В моем случае

IEnumerable<GroupedBusModelsSelectable> BusModels

это работает. Теперь я согласен с Ником, я должен рефакторинг спагетти с разметкой стола.

1 Ответ

2 голосов
/ 01 июня 2011

Вам нужно посмотреть, что вы отправляете в браузер. Для заполнения параметра BusModels необходимо отправить в браузер что-то вроде:

<input type="hidden" name="BusModels[0].someProperty" value="whatever" />
<input type="hidden" name="BusModels[0].someOtherProperty" value="whatever" />
<input type="checkbox" name="BusModels[0].someBoolean" />

<input type="hidden" name="BusModels[1].someProperty" value="whatever" />
<input type="hidden" name="BusModels[1].someOtherProperty" value="whatever" />
<input type="checkbox" name="BusModels[1].someBoolean" />

Обратите внимание, что единственное, что изменилось в имени, это значение в квадратных скобках. Есть и другие способы сделать это, но все они являются вариантами этого метода, и вы можете узнать больше о них здесь . Поскольку в списке нет элементов управления для динамического добавления новых элементов, я предлагаю переписать редактор в качестве шаблона и использовать встроенные функции для создания входных данных.

Для этого передайте модель в уже отсортированный частичный вид, а затем вместо foreach используйте простой цикл for и вызовите редактор для индексов вашей модели.

Вид:

@using (Html.BeginForm("ProcessRoute", "Calculator"))
{
    @Html.TextBox("CityArrival", null, new { @style = "width: 300px;" })
    @Html.TextBox("CityDeparture", null, new { @style = "width: 300px;" })
    @{ Html.RenderPartial("BusModelList", Model.BusModels.OrderBy(c => c.Bus.NumPlaces).ToList());  }      
    <input id="submit" type="submit" value="Поиск" />
}

Частичное представление:

@model List<ViewModels.GroupedBusModelsSelectable>

<table>
@foreach (var item in Model)
{
    <tr>
        <td colspan="3" align="left">@item.BusType.Name</td>
    </tr>
    for (int i = 0; i < Model.Count; i++)
    {
        @Html.EditorFor(x => x[i]);
    }
}
</table>

Это должно сработать. Единственное, что я хотел бы упомянуть, это то, что вы разделили таблицу и строки таблицы, что создает тесную связь между представлением и частичным представлением. Лучший способ справиться с этим - удалить муфту и поместить все связанные конструкции в одно и то же место. Самый простой и чистый способ сделать это - использовать встроенный шаблон бритвы или вообще отойти от таблицы, потому что семантические редакторы не являются табличными данными.

...