This problem has been plaguing me for two days now. There are some similar posts, but none that address my problem completely.
Using MVC-3, Razor syntax:
-- 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; } }
So whats the problem? Well, when the "Complete Edit!" button is pressed, the MyController's Edit is called, as expected with all the MyMainModle's data in tact.... except for the list of ThumbnailModel's - those turn out to be null.
How is this supposed to be done? I have tried many different approaches to this including making an editable template and using EditFor(o=>... all to no avail (this became confusing as I didn't know if the EditFor was supposed to be for the entire collection or just a single item in the collection - I tried both ways). All used to work until I added the complexity of the checkbox for deletion, therefore needing to retrieve the list of ThumbnailModels to check that internal Delete property value.
Thank you all for reading and trying to understand this.
[Disclaimer - some variable and method names have been changed to protect the innocent program. A lot of code has been stripped away and replaced by comment code.]
What is an MVC model? An MVC model contains all of your application logic that is not contained in a view or a controller. The model should contain all of your application business logic, validation logic, and database access logic.
In fact, in ASP.NET MVC, there are three distinct types of model: the domain model, view model and input model.
Introduction. In MVC, we cannot use multiple model tag on a view. But many times, we need to pass multiple models from controller to view or we want to show data from multiple model on a view.
Here's an example that I've put to illustrate some concepts:
Model:
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; } }
Controller:
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 } }
View:
@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!" /> }
Editor template: (~/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)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With