2016-06-01 7 views
0

Я пытаюсь написать страницу, которая извлекает список из таблицы SQL и отображает его, чтобы пользователи могли вносить изменения. Я уже могу отображать информацию. У меня проблемы с отправкой. Я не могу определить способ ввода введенных данных и отправки изменений в список <>, чтобы я мог манипулировать им в контроллере/модели.C# MVC отправить и получить список <> в/из представления с использованием одной модели

В настоящее время я помещаю новые данные в массивы после отправки. Так как я использую @model List<modelname> в представлении. Можно ли заменить значения или, возможно, поместить данные в новый список из представления?

ответ

0

Вы можете это сделать абсолютно, но люди изначально имеют тенденцию сталкиваться с проблемами, поэтому я приведу полный пример.

Для начала давайте определим HomeController, который имеет Index действие, которое возвращает List<EmployeeViewModel>:

public class HomeController : Controller 
{ 
    public ActionResult Index() 
    { 
     // Assume this would really come from your database. 
     var employees = new List<EmployeeViewModel>() 
     { 
      new EmployeeViewModel { Id = 1, Name = "Employee 1" }, 
      new EmployeeViewModel { Id = 2, Name = "Employee 2" }, 
      new EmployeeViewModel { Id = 3, Name = "Employee 3" }, 
     }; 

     return View(employees); 
    } 

    [HttpPost] 
    public ActionResult Index(List<EmployeeViewModel> employees) 
    { 
     // Rest of action 
    } 
} 

Типичными как люди первым подойти к этой проблеме является сделать что-то вроде следующего в index.cshtml:

@model List<EmployeeViewModel> 

@using (Html.BeginForm()) 
{ 
    foreach (var item in Model) 
    { 
     <div class="row"> 
      @Html.EditorFor(x => item.Id) 
     </div> 
     <div class="row"> 
      @Html.EditorFor(x => item.Name) 
     </div> 
    } 

    <input type="submit" /> 
} 

На первый взгляд это выглядело бы так, как будто это сработает. Однако, если вы поместите контрольную точку в действие POST и нажмите кнопку отправки, вы заметите, что employees - null. Причина этого в том, что цикл foreach генерирует HTML вроде следующего:

<input name="item.Id" type="number" value="1" /> 
<input name="item.Name" type="text" value="Employee 1" /> 
<input name="item.Id" type="number" value="2" /> 
<input name="item.Name" type="text" value="Employee 2" /> 
<input name="item.Id" type="number" value="3" /> 
<input name="item.Name" type="text" value="Employee 3" /> 

Я раздели некоторые ненужные части, но обратите внимание, как name атрибуты имеют одинаковые значения для каждого сотрудника. Когда связующее устройство по умолчанию пытается создать список данных на сервере, оно должно быть способным различать разных сотрудников, и, поскольку оно не может, оно приводит к тому, что в списке есть null.

Так почему же он генерирует одни и те же значения? Именно из-за этого:

@Html.EditorFor(x => item.Id) 
@Html.EditorFor(x => item.Name) 

Мы не передавая значение индекса для метода с HtmlHelper вызовов, так что информация не делает его к сгенерированной HTML. Мы можем исправить это, просто сделав использование for петли вместо:

for (int i = 0; i < Model.Count; i++) 
{ 
    @Html.EditorFor(x => Model[i].Id) 
    @Html.EditorFor(x => Model[i].Name) 
} 

Как мы теперь поставляем индекс с каждым вызовом метода, сгенерированный HTML делает сейчас содержит индекс для каждого сотрудника:

<input name="[0].Id" type="number" value="1" /> 
<input name="[0].Name" type="text" value="Employee 1" /> 
<input name="[1].Id" type="number" value="2" /> 
<input name="[1].Name" type="text" value="Employee 2" /> 
<input name="[2].Id" type="number" value="3" /> 
<input name="[2].Name" type="text" value="Employee 3" /> 

Это позволяет связующему объекту по умолчанию связывать Id и Name с каждым EmployeeViewModel, что позволяет ему правильно построить тип на сервере.

На данный момент ваша проблема решена, однако не рекомендуется использовать цикл for, если вы можете избежать этого, что приводит нас к шаблонам редактора. Шаблоны редактора - это HtmlHelper методы, которые позволяют нам отображать настраиваемый шаблон (т. Е. Представление) для заданного типа. Поэтому позвольте мне показать вам пример того, как это сделать с приведенным выше примером.

Для начала, вам необходимо сделать следующее:

  1. Создать EditorTemplates папку внутри папки ~/Views/Home/ (имя EditorTemplates имеет особое значение в MVC, поэтому очень важно, чтобы записать это правильно) ,
  2. Создайте вид EmployeeViewModel.cshtml внутри этой папки (опять же, здесь важно имя: оно должно совпадать с именем типа, для которого вы хотите создать собственный шаблон).

После того, как вы сделали это, он должен выглядеть следующим образом:

Editor templates example

Теперь откройте EmployeeViewModel.cshtml, и поместите код визуализации из Index.cs внутри него:

@model EmployeeViewModel 

<div class="row"> 
    @Html.EditorFor(x => x.Id) 
</div> 
<div class="row"> 
    @Html.EditorFor(x => x.Name) 
</div> 

И, наконец, откройте index.cshtml и измените его на следующее:

@model List<EmployeeViewModel> 

@using (Html.BeginForm()) 
{ 
    @Html.EditorFor(x => x) 

    <input type="submit" /> 
} 

Html.EditorFor, и Html.DisplayFor, оба достаточно умны, чтобы понять, когда они называют для коллекции, так что они выглядят для пользовательского шаблона для визуализации типа коллекции (в данном случае, EditorFor будет искать шаблон редактора для EmployeeViewModel).

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

Конечный результат заключается в том, что привязка к модели упрощается, а не только код для ваших представлений проще, он также разбивается на основе задействованных типов, что упрощает работу с вашими представлениями, а не с гигантский вид, который делает все.

Следует также упомянуть, что, поскольку мой пример непосредственно используется в коллекции, и ничего более, вы можете фактически заменить @Html.EditorFor(x => x) на @Html.EditorForModel(). Я не делал этого изначально, так как не хотел создавать впечатление, что шаблоны вызываются только с использованием последнего.

+1

О, ничего себе! Огромное спасибо!! –

+0

@HarporSydney Добро пожаловать. :) –