2016-06-01 1 views
0

Je tente d'écrire une page qui récupère une liste <> à partir d'une table SQL et l'affiche afin que les utilisateurs puissent apporter des modifications. Je suis déjà en mesure d'afficher les informations. Je rencontre des problèmes avec la soumission. Je suis incapable de trouver un moyen de prendre les données saisies et envoyer les modifications à une liste <> afin que je puisse le manipuler dans le contrôleur/modèle.C# MVC envoyer et récupérer une liste <> vers/depuis une vue en utilisant un modèle

Actuellement, je place les nouvelles données dans des tableaux lors de la soumission. Depuis que j'utilise @model List<modelname> dans la vue. Est-il possible de remplacer les valeurs ou éventuellement mettre les données dans une nouvelle liste à partir de la vue?

Répondre

0

Vous pouvez absolument faire cela, mais au début, les gens ont tendance à avoir des problèmes, alors je vais vous donner un exemple complet.

Pour commencer, nous allons définir une HomeController qui a une action Index qui retourne une 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 
    } 
} 

La manière dont typique première approche de ce problème est de faire quelque chose comme ce qui suit dans index.cshtml:

À première vue, cela semblerait fonctionner. Toutefois, si vous placez un point d'arrêt dans l'action POST et cliquez sur le bouton Envoyer, vous remarquerez que employees est null. La raison en est que la boucle foreach génère HTML comme ce qui suit:

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

J'ai dépouillé quelques parties non pertinentes là, mais remarquez comment les name attributs ont les mêmes valeurs pour chaque employé. Lorsque le classeur de modèle par défaut tente de construire la liste de données sur le serveur, il doit être capable de distinguer les différents employés, et, parce qu'il ne peut pas, il en résulte que la liste est null. Pourquoi donc génère-t-il les mêmes valeurs? Il est pour cette raison:

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

Nous ne sommes pas passer une valeur d'index aux appels de méthode HtmlHelper, de sorte que l'information ne permet pas au code HTML généré. Nous pouvons résoudre ce problème simplement en utilisant une boucle for à la place:

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

Comme nous fournit maintenant un indice à chaque appel de méthode, le code HTML généré ne contient maintenant un index pour chaque employé:

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

Cela permet au classeur de modèle par défaut d'associer un Id et un Name à chaque EmployeeViewModel, ce qui lui permet de construire correctement le type sur le serveur.

À ce stade, votre problème est résolu, cependant, il n'est pas recommandé d'utiliser une boucle for si vous pouvez l'éviter, ce qui nous amène à des modèles d'éditeur. Les modèles d'éditeur sont des méthodes HtmlHelper qui nous permettent de rendre un modèle personnalisé (c'est-à-dire une vue) pour un type donné. Alors laissez-moi vous montrer un exemple de la façon de le faire avec l'exemple de code ci-dessus.

Pour commencer, vous aurez besoin de faire ce qui suit:

  1. Créez un dossier EditorTemplates intérieur de votre dossier ~/Views/Home/ (le nom EditorTemplates a une signification particulière dans MVC, il est donc important de préciser correctement) .
  2. Créez une vue EmployeeViewModel.cshtml à l'intérieur de ce dossier (encore une fois, le nom est important ici: il doit correspondre au nom du type pour lequel vous souhaitez créer un modèle personnalisé).

Une fois que vous avez fait cela, il devrait ressembler à ceci:

Editor templates example

Maintenant, ouvrez EmployeeViewModel.cshtml, et de mettre votre code de rendu de Index.cs à l'intérieur de celui-ci:

@model EmployeeViewModel 

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

Enfin, ouvrez index.cshtml et remplacez-le par le suivant:

@model List<EmployeeViewModel> 

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

    <input type="submit" /> 
} 

Html.EditorFor et Html.DisplayFor, sont à la fois assez intelligent pour reconnaître quand ils sont appelés pour une collection, donc ils cherchent un modèle personnalisé pour rendre le type de la collection (dans ce cas, EditorFor recherchera un modèle d'éditeur pour EmployeeViewModel). Comme nous avons fourni un modèle d'éditeur, non seulement il le rendra pour chaque élément de la collection, mais il générera également les indices corrects pour chacun de ces éléments, donnant au relieur du modèle toutes les informations dont il a besoin pour reconstruire cette collection sur le serveur. Le résultat final est que la liaison de modèle devient plus simple, et non seulement le code pour vos vues est plus simple, mais il est également divisé en fonction des types impliqués, ce qui rend vos vues plus faciles à utiliser, par opposition à vue géante qui fait tout.

Je devrais également mentionner que comme mon exemple utilise directement une collection, et rien de plus, vous pouvez effectivement remplacer @Html.EditorFor(x => x) par @Html.EditorForModel(). Je ne l'ai pas fait au départ car je ne voulais pas donner l'impression que les modèles sont appelés simplement en utilisant ce dernier.

+1

Oh ouah! Merci beaucoup!! –

+0

@HarporSydney De rien. :) –