2012-10-03 11 views
8

Mi piacerebbe sapere come posso utilizzare il mio ViewModel sull'azione Crea? Ho provato diversi esempi che ho trovato qui nel forum, ma nessuno ha risolto il mio problema. Mi sto tormentando per qualche giorno, ma non riesco a capire cosa c'è che non va.Errore MVC ViewModel - Nessun costruttore parametrico definito per questo oggetto

Ogni volta che faccio clic sul pulsante Crea ottengo il seguente errore: Nessun costruttore senza parametri definito per questo oggetto.

@model MvcMusicStore.ViewModels.AlbumViewModel 

@{ 
    ViewBag.Title = "Create"; 
} 

<h2>Create</h2> 

<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script> 
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script> 

@using (Html.BeginForm()) { 
    @Html.ValidationSummary(true) 
    <fieldset> 
     <legend>Album</legend> 

     <div class="editor-label"> 
      @Html.LabelFor(model => model.AlbumItem.GenreId, "Genre") 
     </div> 
     <div class="editor-field"> 
      @Html.DropDownList("Genres", String.Empty) 
      @Html.ValidationMessageFor(model => model.AlbumItem.GenreId) 
     </div> 

     <div class="editor-label"> 
      @Html.LabelFor(model => model.AlbumItem.ArtistId, "Artist") 
     </div> 
     <div class="editor-field"> 
      @Html.DropDownList("Artists", String.Empty) 
      @Html.ValidationMessageFor(model => model.AlbumItem.ArtistId) 
     </div> 

     <div class="editor-label"> 
      @Html.LabelFor(model => model.AlbumItem.Title) 
     </div> 
     <div class="editor-field"> 
      @Html.EditorFor(model => model.AlbumItem.Title) 
      @Html.ValidationMessageFor(model => model.AlbumItem.Title) 
     </div> 

     <div class="editor-label"> 
      @Html.LabelFor(model => model.AlbumItem.Price) 
     </div> 
     <div class="editor-field"> 
      @Html.EditorFor(model => model.AlbumItem.Price) 
      @Html.ValidationMessageFor(model => model.AlbumItem.Price) 
     </div> 

     <div class="editor-label"> 
      @Html.LabelFor(model => model.AlbumItem.AlbumArtUrl) 
     </div> 
     <div class="editor-field"> 
      @Html.EditorFor(model => model.AlbumItem.AlbumArtUrl) 
      @Html.ValidationMessageFor(model => model.AlbumItem.AlbumArtUrl) 
     </div> 

     <p> 
      <input type="submit" value="Create" /> 
     </p> 
    </fieldset> 
} 

<div> 
    @Html.ActionLink("Back to List", "Index") 
</div> 

Create.cshtml

public class StoreManagerController : Controller 
     { 
      private MusicStoreDB db = new MusicStoreDB(); 

      // 
      // GET: /StoreManager/Create 

      public ActionResult Create() 
      { 
       var viewModel = new AlbumViewModel() 
       { 
        Genres = new SelectList(db.Genres, "GenreId", "Name"), 
        Artists = new SelectList(db.Artists, "ArtistId", "Name") 
       }; 
       return View(viewModel); 
      } 

      // 
      // POST: /StoreManager/Create 

      [HttpPost] 
      public ActionResult Create(AlbumViewModel vm) 
      { 
       if (ModelState.IsValid) 
       { 
        db.Albums.Add(vm.AlbumItem); 
        db.SaveChanges(); 
        return RedirectToAction("Index"); 
       } 

       vm.Genres = new SelectList(db.Genres, "GenreId", "Name", vm.AlbumItem.GenreId); 
       vm.Artists = new SelectList(db.Artists, "ArtistId", "Name", vm.AlbumItem.ArtistId); 
       return View(vm); 
      } 
} 

StoreManager.cs - Snippet

public class AlbumViewModel 
    { 
     public AlbumViewModel() 
     { 
      // nothing 
     } 

     public Album AlbumItem { get; set; } 
     public SelectList Genres { get; set; } 
     public SelectList Artists { get; set; } 
    } 

public class Album 
    { 
     public Album() 
     { 
      // nothing 
     } 

     public virtual int AlbumId { get; set; } 
     public virtual int GenreId { get; set; } 
     public virtual int ArtistId { get; set; } 
     public virtual string Title { get; set; } 
     public virtual decimal Price { get; set; } 
     public virtual string AlbumArtUrl { get; set; } 
     public virtual Genre Genre { get; set; } 
     public virtual Artist Artist { get; set; } 
    } 

public class Artist 
    { 
     public Artist() 
     { 
      // nothing 
     } 

     public virtual int ArtistId { get; set; } 
     public virtual string Name { get; set; } 
    } 

public class Genre 
    { 
     public Genre() 
     { 
      // nothing 
     } 

     public virtual int GenreId { get; set; } 
     public virtual string Name { get; set; } 
     public virtual string Description { get; set; } 
     public virtual List<Album> Albums { get; set; } 
    } 
+1

What's 'Genere'? – SLaks

+0

Aggiunto 'Genere' e' Artista' nel codice sopra. – fvss

+0

L'unica cosa che sembra non avere un costruttore senza parametri è la SelectList (http://msdn.microsoft.com/en-us/library/system.web.mvc.selectlist(v=vs.108).aspx). E se commentaste quelli? –

risposta

24

Se avessi un centesimo per ogni volta che ho visto questo problema. In genere è correlato alla denominazione delle proprietà del modello e al modo in cui vengono utilizzate in un DropDownList. Il 99,999% delle volte è perché le persone utilizzano Html.DropDownList() e lo chiamano allo stesso modo del loro SelectList. Questa è una delle ragioni per cui dovresti usare lo DropDownListFor fortemente tipizzato.

In questo caso, il problema è che devi SelectList s nome Genres e Artists, quindi a suo avviso si dispone:

@Html.DropDownList("Genres", String.Empty) 
@Html.DropDownList("Artists", String.Empty) 

Sede, lo stesso nome.

Che cosa si deve fare è modificare il modello per rendere SelectList s denominato GenreList e ArtistList. Quindi, modifica la visualizzazione per utilizzare il modello fortemente tipizzato.

@Html.DropDownListFor(m => m.AlbumItem.GenreID, Model.GenreList) 
@Html.DropDownListFor(m => m.AlbumItem.ArtistID, Model.ArtistList) 

Il motivo è che si sta pubblicando un valore chiamato Generi sul controller. Il raccoglitore modello predefinito guarda doverosamente nel modello per trovare qualcosa chiamato Generi e istanziarlo. Ma, piuttosto che un ID o una stringa, trova una SelectList di nome Genres, e quando tenta di istanziarla, trova che non esiste un costruttore predefinito.

Quindi il tuo errore. SO è pieno di domande che chiedono questa stessa cosa.

+0

Questo è tutto! Grazie! – fvss

+0

Lo stesso qui. Mi hai salvato diverse ore –

0

Simile a Erik Funkenbusch's answer avrei aggiunto una DropDownList alla mia forma, ma nel mio caso non è stato (e non era destinata ad essere) presentati con la forma come lo era al di fuori dei <form></form> tags:

@Html.DropDownList("myField", Model.MyField) 

Poiché il modello conteneva il campo solo per la visualizzazione, anche questo ha causato l'errore No parameterless constructor defined for this object perché il campo non è stato inviato affatto.

In questo caso sono fissati aggiungendo un exclude vincolante:

public ActionResult Foo(int id, int? page, [Bind(Exclude = "MyField")]MyModel model) 
0

Per me il problema ha partecipato al metodo stesso BeginForm(). Sembrava questo:

@using (Html.BeginForm("MyAccount", "MyController", Model)) 

Copiato e incollato dalla pagina di accesso di un altro progetto, che non ha un menu a discesa.

In ogni caso, rimuovere il modello dall'elenco dei parametri e tutto funziona perfettamente :)

Problemi correlati