Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
In Esplora soluzioni fare clic con il pulsante destro del mouse sulla cartella Controller e quindi scegliere Aggiungi controller. Assegnare al controller il nome StoreManagerController. Impostare le opzioni per la finestra di dialogo Aggiungi controller , come illustrato nell'immagine seguente.
Modificare la vista StoreManager\Index.cshtml e rimuovere AlbumArtUrl
. La rimozione AlbumArtUrl
rende la presentazione più leggibile. Il codice completo è illustrato di seguito.
@model IEnumerable<MvcMusicStore.Models.Album>
@{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<p>
@Html.ActionLink("Create New", "Create")
</p>
<table>
<tr>
<th>
Genre
</th>
<th>
Artist
</th>
<th>
Title
</th>
<th>
Price
</th>
<th></th>
</tr>
@foreach (var item in Model) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.Genre.Name)
</td>
<td>
@Html.DisplayFor(modelItem => item.Artist.Name)
</td>
<td>
@Html.DisplayFor(modelItem => item.Title)
</td>
<td>
@Html.DisplayFor(modelItem => item.Price)
</td>
<td>
@Html.ActionLink("Edit", "Edit", new { id=item.AlbumId }) |
@Html.ActionLink("Details", "Details", new { id=item.AlbumId }) |
@Html.ActionLink("Delete", "Delete", new { id=item.AlbumId })
</td>
</tr>
}
</table>
Aprire il file Controllers\StoreManagerController.cs e trovare il Index
metodo . Aggiungere la OrderBy
clausola in modo che gli album vengano ordinati in base al prezzo. Di seguito è riportato il codice completo.
public ViewResult Index()
{
var albums = db.Albums.Include(a => a.Genre).Include(a => a.Artist)
.OrderBy(a => a.Price);
return View(albums.ToList());
}
L'ordinamento in base al prezzo consentirà di testare più facilmente le modifiche apportate al database. Quando si testano i metodi di modifica e creazione, è possibile usare un prezzo basso in modo che i dati salvati vengano visualizzati per primi.
Aprire il file StoreManager\Edit.cshtml . Aggiungere la riga seguente subito dopo il tag legenda.
@Html.HiddenFor(model => model.AlbumId)
Il codice seguente illustra il contesto di questa modifica:
@using (Html.BeginForm()) {
@Html.ValidationSummary(true)
<fieldset>
<legend>Album</legend>
@Html.HiddenFor(model => model.AlbumId)
<div class="editor-label">
@Html.LabelFor(model => model.GenreId, "Genre")
</div>
<div class="editor-field">
@Html.DropDownList("GenreId", String.Empty)
@Html.ValidationMessageFor(model => model.GenreId)
</div>
<!-- Items removed for brevity. -->
}
È AlbumId
necessario per apportare modifiche a un record album.
Premere CTRL+F5 per eseguire l'applicazione. Selezionare il collegamento Admin (Amministratore ) e quindi selezionare il collegamento Create New (Crea nuovo ) per creare un nuovo album. Verificare che le informazioni sull'album siano state salvate. Modificare un album e verificare che le modifiche apportate siano persistenti.
The Album Schema
Il StoreManager
controller creato dal meccanismo di scaffolding MVC consente l'accesso CRUD (Create, Read, Update, Delete) agli album nel database music store. Lo schema per le informazioni sugli album è illustrato di seguito:
La Albums
tabella non archivia il genere dell'album e la descrizione, archivia una chiave esterna nella Genres
tabella. La Genres
tabella contiene il nome e la descrizione del genere. Analogamente, la Albums
tabella non contiene il nome degli artisti dell'album, ma una chiave esterna per la Artists
tabella. La Artists
tabella contiene il nome dell'artista. Se si esaminano i dati nella Albums
tabella, ogni riga contiene una chiave esterna per la Genres
tabella e una chiave esterna nella Artists
tabella. L'immagine seguente mostra alcuni dati di tabella della Albums
tabella.
Tag di selezione HTML
L'elemento HTML (creato dall'helper DropDownList HTML <select>
) viene usato per visualizzare un elenco completo di valori (ad esempio l'elenco di generi). Per modificare i moduli, quando il valore corrente è noto, l'elenco di selezione può visualizzare il valore corrente. Abbiamo visto questo in precedenza quando impostiamo il valore selezionato su Comedy. L'elenco di selezione è ideale per la visualizzazione di dati di chiave esterna o di categoria. L'elemento <select>
per la chiave esterna Genre visualizza l'elenco dei possibili nomi di genere, ma quando si salva la maschera la proprietà Genre viene aggiornata con il valore di chiave esterna Genre, non con il nome del genere visualizzato. Nell'immagine seguente il genere selezionato è Disco e l'artista è Donna Summer.
Esame del codice Scaffolding MVC ASP.NET
Aprire il file Controllers\StoreManagerController.cs e trovare il HTTP GET Create
metodo .
public ActionResult Create()
{
ViewBag.GenreId = new SelectList(db.Genres, "GenreId", "Name");
ViewBag.ArtistId = new SelectList(db.Artists, "ArtistId", "Name");
return View();
}
Il Create
metodo aggiunge due oggetti SelectList a ViewBag
, uno per contenere le informazioni sul genere e uno per contenere le informazioni sull'artista. L'overload del costruttore SelectList usato in precedenza accetta tre argomenti:
public SelectList(
IEnumerable items,
string dataValueField,
string dataTextField
)
- items: IEnumerable contenente gli elementi nell'elenco. Nell'esempio precedente l'elenco dei generi restituiti da
db.Genres
. - dataValueField: nome della proprietà nell'elenco IEnumerable che contiene il valore della chiave. Nell'esempio precedente e
GenreId
ArtistId
. - dataTextField: nome della proprietà nell'elenco IEnumerable che contiene le informazioni da visualizzare. Sia nell'artista che nella tabella di genere, il
name
campo viene usato.
Aprire il file Views\StoreManager\Create.cshtml ed esaminare il Html.DropDownList
markup helper per il campo genere.
@model MvcMusicStore.Models.Album
@* Markup removed for clarity.*@
@Html.DropDownList("GenreId", String.Empty)
La prima riga mostra che la visualizzazione di creazione accetta un Album
modello. Create
Nel metodo illustrato in precedenza non è stato passato alcun modello, quindi la vista ottiene un modello NullAlbum
. A questo punto stiamo creando un nuovo album in modo da non avere dati Album
per esso.
L'overload Html.DropDownList illustrato sopra accetta il nome del campo da associare al modello. Usa anche questo nome per cercare un oggetto ViewBag contenente un oggetto SelectList . Usando questo overload, è necessario denominare l'oggetto GenreId
ViewBag SelectList . Il secondo parametro (String.Empty
) è il testo da visualizzare quando non è selezionato alcun elemento. Questo è esattamente ciò che vogliamo quando creiamo un nuovo album. Se è stato rimosso il secondo parametro e si è usato il codice seguente:
@Html.DropDownList("GenreId")
Per impostazione predefinita, l'elenco di selezione corrisponde al primo elemento o a Rock nell'esempio.
Esame del HTTP POST Create
metodo .
//
// POST: /StoreManager/Create
[HttpPost]
public ActionResult Create(Album album)
{
if (ModelState.IsValid)
{
db.Albums.Add(album);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.GenreId = new SelectList(db.Genres, "GenreId", "Name",
album.GenreId);
ViewBag.ArtistId = new SelectList(db.Artists, "ArtistId", "Name",
album.ArtistId);
return View(album);
}
Questo overload del Create
metodo accetta un album
oggetto creato dal sistema di associazione di modelli MVC ASP.NET dai valori del modulo pubblicati. Quando si invia un nuovo album, se lo stato del modello è valido e non sono presenti errori di database, il nuovo album viene aggiunto al database. L'immagine seguente mostra la creazione di un nuovo album.
È possibile usare lo strumento fiddler per esaminare i valori del modulo pubblicati che ASP.NET binding di modelli MVC usa per creare l'oggetto album.
.
Refactoring della creazione di ViewBag SelectList
Sia i Edit
metodi che il HTTP POST Create
metodo hanno codice identico per configurare SelectList in ViewBag. Nello spirito di DRY, il refactoring di questo codice verrà refactoring. Questo codice sottoposto a refactoring verrà usato in un secondo momento.
Creare un nuovo metodo per aggiungere un genere e un artista SelectList a ViewBag.
private void SetGenreArtistViewBag(int? GenreID = null, int? ArtistID = null) {
if (GenreID == null)
ViewBag.GenreId = new SelectList(db.Genres, "GenreId", "Name");
else
ViewBag.GenreId = new SelectList(db.Genres.ToArray(), "GenreId", "Name", GenreID);
if (ArtistID == null)
ViewBag.ArtistId = new SelectList(db.Artists, "ArtistId", "Name");
else
ViewBag.ArtistId = new SelectList(db.Artists, "ArtistId", "Name", ArtistID);
}
Sostituire le due righe impostando in ViewBag
ognuno dei Create
metodi e Edit
con una chiamata al SetGenreArtistViewBag
metodo . Il codice completo è illustrato di seguito.
//
// GET: /StoreManager/Create
public ActionResult Create() {
SetGenreArtistViewBag();
return View();
}
//
// POST: /StoreManager/Create
[HttpPost]
public ActionResult Create(Album album) {
if (ModelState.IsValid) {
db.Albums.Add(album);
db.SaveChanges();
return RedirectToAction("Index");
}
SetGenreArtistViewBag(album.GenreId, album.ArtistId);
return View(album);
}
//
// GET: /StoreManager/Edit/5
public ActionResult Edit(int id) {
Album album = db.Albums.Find(id);
SetGenreArtistViewBag(album.GenreId, album.ArtistId);
return View(album);
}
//
// POST: /StoreManager/Edit/5
[HttpPost]
public ActionResult Edit(Album album) {
if (ModelState.IsValid) {
db.Entry(album).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
SetGenreArtistViewBag(album.GenreId, album.ArtistId);
return View(album);
}
Creare un nuovo album e modificare un album per verificare il lavoro delle modifiche.
Passaggio esplicito di SelectList all'elenco a discesa
La creazione e la modifica delle visualizzazioni create dal ASP.NET scaffolding MVC usano l'overload DropDownList seguente:
public static MvcHtmlString DropDownList(
this HtmlHelper htmlHelper,
string name, // The name of the ViewModel property to bind.
string optionLabel // The string added to the top of the list
// typically String.Empty or "Select a Genre"
)
Il DropDownList
markup per la visualizzazione di creazione è illustrato di seguito.
@Html.DropDownList("GenreId", String.Empty)
Poiché la ViewBag
proprietà per SelectList
è denominata GenreId
, l'helper DropDownList userà GenreId
SelectList in ViewBag. Nell'overload DropDownList seguente l'oggetto SelectList
viene passato in modo esplicito.
public static MvcHtmlString DropDownList(
this HtmlHelper htmlHelper,
string name, // The name of the ViewModel property to bind.
IEnumerable selectList // The SelectList
)
Aprire il file Views\StoreManager\Edit.cshtml e modificare la chiamata DropDownList in modo da passare in modo esplicito selectList usando l'overload precedente. Eseguire questa operazione per la categoria Genere. Il codice completato è illustrato di seguito:
@Html.DropDownList("GenreId", ViewBag.GenreId as SelectList)
Eseguire l'applicazione e fare clic sul collegamento Amministratore , quindi passare a un album Jazz e selezionare il collegamento Modifica .
Invece di visualizzare Jazz come genere attualmente selezionato, viene visualizzato Rock. Quando l'argomento stringa (la proprietà da associare) e l'oggetto SelectList hanno lo stesso nome, il valore selezionato non viene utilizzato. Quando non è specificato alcun valore selezionato, per impostazione predefinita il browser corrisponde al primo elemento di SelectList(che è Rock nell'esempio precedente). Si tratta di una limitazione nota dell'helper DropDownList .
Aprire il file Controllers\StoreManagerController.cs e modificare i nomi degli oggetti SelectList in Genres
e Artists
. Il codice completato è illustrato di seguito:
private void SetGenreArtistViewBag(int? GenreID = null, int? ArtistID = null) {
if (GenreID == null)
ViewBag.Genres = new SelectList(db.Genres, "GenreId", "Name");
else
ViewBag.Genres = new SelectList(db.Genres.ToArray(), "GenreId", "Name", GenreID);
if (ArtistID == null)
ViewBag.Artists = new SelectList(db.Artists, "ArtistId", "Name");
else
ViewBag.Artists = new SelectList(db.Artists, "ArtistId", "Name", ArtistID);
}
I nomi Generi e Artisti sono nomi migliori per le categorie, in quanto contengono più che solo l'ID di ogni categoria. Il refactoring eseguito in precedenza è stato pagato. Invece di modificare ViewBag in quattro metodi, le modifiche sono state isolate nel SetGenreArtistViewBag
metodo .
Modificare la chiamata DropDownList nelle visualizzazioni di creazione e modifica per usare i nuovi nomi SelectList . Di seguito è riportato il nuovo markup per la visualizzazione di modifica:
<div class="editor-label">
@Html.LabelFor(model => model.GenreId, "Genre")
</div>
<div class="editor-field">
@Html.DropDownList("GenreId", ViewBag.Genres as SelectList)
@Html.ValidationMessageFor(model => model.GenreId)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.ArtistId, "Artist")
</div>
<div class="editor-field">
@Html.DropDownList("ArtistId", ViewBag.Artists as SelectList)
@Html.ValidationMessageFor(model => model.ArtistId)
</div>
La visualizzazione Crea richiede una stringa vuota per impedire la visualizzazione del primo elemento nell'oggetto SelectList.
<div class="editor-label">
@Html.LabelFor(model => model.GenreId, "Genre" )
</div>
<div class="editor-field">
@Html.DropDownList("GenreId", ViewBag.Genres as SelectList, String.Empty)
@Html.ValidationMessageFor(model => model.GenreId)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.ArtistId, "Artist")
</div>
<div class="editor-field">
@Html.DropDownList("ArtistId", ViewBag.Artists as SelectList, String.Empty)
@Html.ValidationMessageFor(model => model.ArtistId)
</div>
Creare un nuovo album e modificare un album per verificare il lavoro delle modifiche. Testare il codice di modifica selezionando un album con un genere diverso da Rock.
Uso di un modello di visualizzazione con l'helper DropDownList
Creare una nuova classe nella cartella ViewModels denominata AlbumSelectListViewModel
. Sostituire il codice nella AlbumSelectListViewModel
classe con quanto segue:
using MvcMusicStore.Models;
using System.Web.Mvc;
using System.Collections;
namespace MvcMusicStore.ViewModels {
public class AlbumSelectListViewModel {
public Album Album { get; private set; }
public SelectList Artists { get; private set; }
public SelectList Genres { get; private set; }
public AlbumSelectListViewModel(Album album,
IEnumerable artists,
IEnumerable genres) {
Album = album;
Artists = new SelectList(artists, "ArtistID", "Name", album.ArtistId);
Genres = new SelectList(genres, "GenreID", "Name", album.GenreId);
}
}
}
Il AlbumSelectListViewModel
costruttore accetta un album, un elenco di artisti e generi e crea un oggetto contenente l'album e un per SelectList
generi e artisti.
Compilare il progetto in modo che AlbumSelectListViewModel
sia disponibile quando si crea una visualizzazione nel passaggio successivo.
Aggiungere un EditVM
metodo all'oggetto StoreManagerController
. Il codice completo è illustrato di seguito.
//
// GET: /StoreManager/EditVM/5
public ActionResult EditVM(int id) {
Album album = db.Albums.Find(id);
if (album == null)
return HttpNotFound();
AlbumSelectListViewModel aslvm = new AlbumSelectListViewModel(album, db.Artists, db.Genres);
return View(aslvm);
}
Fare clic con il pulsante destro del mouse su AlbumSelectListViewModel
, selezionare Risolvi, quindi usare MvcMusicStore.ViewModels;.
In alternativa, è possibile aggiungere l'istruzione using seguente:
using MvcMusicStore.ViewModels;
Fare clic con il pulsante destro del mouse EditVM
e selezionare Aggiungi visualizzazione. Usare le opzioni illustrate di seguito.
Selezionare Aggiungi, quindi sostituire il contenuto del file Views\StoreManager\EditVM.cshtml con quanto segue:
@model MvcMusicStore.ViewModels.AlbumSelectListViewModel
@{
ViewBag.Title = "EditVM";
}
<h2>Edit VM</h2>
@using (Html.BeginForm("Edit","StoreManager",FormMethod.Post)) {
@Html.ValidationSummary(true)
<fieldset>
<legend>Album</legend>
@Html.HiddenFor(model => model.Album.AlbumId )
<div class="editor-label">
@Html.LabelFor(model => model.Album.GenreId, "Genre")
</div>
<div class="editor-field">
@Html.DropDownList("Album.GenreId", Model.Genres)
@Html.ValidationMessageFor(model => model.Album.GenreId)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.Album.ArtistId, "Artist")
</div>
<div class="editor-field">
@Html.DropDownList("Album.ArtistId", Model.Artists)
@Html.ValidationMessageFor(model => model.Album.ArtistId)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.Album.Title)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Album.Title)
@Html.ValidationMessageFor(model => model.Album.Title)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.Album.Price)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Album.Price)
@Html.ValidationMessageFor(model => model.Album.Price)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.Album.AlbumArtUrl)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Album.AlbumArtUrl)
@Html.ValidationMessageFor(model => model.Album.AlbumArtUrl)
</div>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
<div>
@Html.ActionLink("Back to List", "Index")
</div>
Il EditVM
markup è molto simile al markup originale Edit
con le eccezioni seguenti.
- Le proprietà del modello nella
Edit
visualizzazione sono del modulomodel.property
, ad esempiomodel.Title
. Le proprietà del modello nellaEditVm
visualizzazione sono del modulomodel.Album.property
, ad esempiomodel.Album.Title
. Ciò è dovuto al fatto che laEditVM
vista viene passata a un contenitore per unAlbum
oggetto , non comeAlbum
nellaEdit
visualizzazione. - Il secondo parametro DropDownList proviene dal modello di visualizzazione, non dal ViewBag.
- L'helper BeginForm nella
EditVM
visualizzazione esegue in modo esplicito il postback alEdit
metodo di azione. Pubblicando nuovamente l'azioneEdit
, non è necessario scrivere un'azioneHTTP POST EditVM
e riutilizzare l'azioneHTTP POST
Edit
.
Eseguire l'applicazione e modificare un album. Modificare l'URL per usare EditVM
. Modificare un campo e premere il pulsante Salva per verificare che il codice funzioni.
Quale approccio è consigliabile usare?
Tutti e tre gli approcci illustrati sono accettabili. Molti sviluppatori preferiscono passare in modo esplicito all'oggetto SelectList
DropDownList
usando .ViewBag
Questo approccio offre il vantaggio di offrire la flessibilità di usare un nome più appropriato per la raccolta. L'unica avvertenza è che non è possibile denominare l'oggetto ViewBag SelectList
con lo stesso nome della proprietà del modello.
Alcuni sviluppatori preferiscono l'approccio ViewModel. Altri considerano il markup più dettagliato e il codice HTML generato dell'approccio ViewModel uno svantaggio.
In questa sezione sono stati appresi tre approcci all'uso di DropDownList con i dati delle categorie. Nella sezione successiva verrà illustrato come aggiungere una nuova categoria.