web-dev-qa-db-fra.com

Modèle contenant la liste des modèles (MVC-3, Razor)

Ce problème me tourmente depuis deux jours maintenant. Il existe des articles similaires, mais aucun ne résout complètement mon problème.

En utilisant MVC-3, la syntaxe Razor:

- EDIT.cshtml -

@using (Html.BeginForm("Edit", "My", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
    <!-- Some fields... -->
    <div class="editor-field">
        @Html.TextAreaFor(m => m.LongDescription)
        @Html.ValidationMessageFor(m => m.LongDescription)
    </div>

    <!-- Some more fields work... Including picture upload (summary).-->
    <input name="button" type="submit" value="Add Picture" />

    <!-- Picture Item display -->
    @foreach(var thumbnail in Model.ThumbnailImagePathAndNames) 
    {
      <img src="@Url.Content(@thumbnail.ThumbnailPicturePath)" alt="" width="200" />
      @Html.RadioButtonFor(o=>o.SelectedImage, @thumbnail.ImageGUID)  Primary Picture 
      <!-- Checkbox to mark for deletion -->
      @Html.CheckBoxFor(o=>thumbnail.Delete) Delete ???????? <!---- Here is a problem - I don't understand how this should work -->
    }
    <input id="Submit1" name="button" type="submit" value="Complete Edit!" />
}

- MyController.cs -

 [HttpPost]
 public ActionResult Edit(String button, HttpPostedFileBase file, MyMainModel model)
 {
     // if button = submit picture,  work with picture here and break(long story)

     // save model data
         // if valid, save and redirect


     // not valid or error, load up view like normal but with error messages
     model.LoadThumbnails();
     return View(model);

 }

- MyMainModel.cs -

public class MyMainModel
{
    // some properties...
     public Guid? SelectedImage { get; set; }

    [Display(Name = "Detailed Description")]
    public String LongDescription { get; set; }

    // some more properties....


    // and finally my list of models
    public IList<ThumbnailModel> ThumbnailImagePathAndNames { get; set; }

    public void LoadThumbnails()
    {
         // load up initial thumbnail models
         this.ThumbnailImagePathAndNames = new List<ThumbnailModel>(readDataService.GetThumbnailModels(this.SomeID));
    }
}

- ThumbnailModels.cs -

public class ThumbnailModel
{
    public Guid ImageGUID { get; set; }
    public String FullSizePicturePath { get; set; }
    public String ThumbnailPicturePath { get; set; }

    public bool Delete { get; set; }
}

Donc quel est le problème? Eh bien, lorsque le "Complete Edit!" bouton est enfoncé, le MyController Edit est appelé, comme prévu avec toutes les données de MyMainModle en tact .... sauf pour la liste des ThumbnailModel - ceux-ci s'avèrent être nuls.

Comment est-ce censé être fait? J'ai essayé de nombreuses approches différentes à ce sujet, y compris la création d'un modèle modifiable et l'utilisation de EditFor (o => ... tout en vain (cela est devenu déroutant car je ne savais pas si le EditFor était censé être pour la collection entière ou simplement un seul élément dans la collection - j'ai essayé dans les deux sens). Tous fonctionnaient jusqu'à ce que j'ajoute la complexité de la case à cocher pour la suppression, il fallait donc récupérer la liste des ThumbnailModels pour vérifier cette valeur interne de la propriété Delete.

Merci à tous d'avoir lu et d'avoir essayé de comprendre cela.

[Avertissement - certains noms de variables et de méthodes ont été modifiés pour protéger le programme innocent. Beaucoup de code a été supprimé et remplacé par du code de commentaire.]

29
Rob

Voici un exemple que j'ai mis pour illustrer certains concepts:

Modèle:

public class MyMainModel
{
    public Guid? SelectedImage { get; set; }
    public string LongDescription { get; set; }

    public IEnumerable<ThumbnailModel> ThumbnailImagePathAndNames { get; set; }

    public HttpPostedFileBase File { get; set; }
}

public class ThumbnailModel
{
    public Guid ImageGUID { get; set; }
    public bool Delete { get; set; }
}

Manette:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        var model = new MyMainModel
        {
            // TODO: fetch from the repository instead of hardcoding
            ThumbnailImagePathAndNames = new[] 
            {
                new ThumbnailModel { ImageGUID = Guid.NewGuid() },
                new ThumbnailModel { ImageGUID = Guid.NewGuid() },
                new ThumbnailModel { ImageGUID = Guid.NewGuid() },
            }
        };
        return View(model);
    }

    [HttpPost]
    public ActionResult Index(MyMainModel model) 
    {
        ... the model will be properly bound here
    }
}

Vue:

@model AppName.Models.MyMainModel
@{
    ViewBag.Title = "Index";
    Layout = "~/Views/Shared/_Layout.cshtml";
}
@using (Html.BeginForm("index", "home", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
    <div class="editor-field">
        @Html.TextAreaFor(m => m.LongDescription)
        @Html.ValidationMessageFor(m => m.LongDescription)
    </div>
    <input type="file" name="file" />
    <!-- Use different names for the upload and complete submit
         buttons so that you can distinguish which one was clicked
         in the POST action 
    -->
    <input name="upload" type="submit" value="Add Picture" />

    @Html.EditorFor(x => x.ThumbnailImagePathAndNames)    
    <input name="complete" type="submit" value="Complete Edit!" />
}

Modèle d'éditeur: (~/Views/Home/EditorTemplates/ThumbnailModel.cshtml):

@model AppName.Models.ThumbnailModel
<!-- Pass the image id as hidden field -->
@Html.HiddenFor(x => x.ImageGUID)
@Html.CheckBoxFor(x => x.Delete)
45
Darin Dimitrov