Überprüfen des Gerüstbaus durch ASP.NET MVC für das DropDownList-Hilfsprogramm
von Rick Anderson
Klicken Sie in Projektmappen-Explorer mit der rechten Maustaste auf den Ordner "Controller", und wählen Sie dann "Controller hinzufügen" aus. Nennen Sie den Controller StoreManagerController. Legen Sie die Optionen für das Dialogfeld "Controller hinzufügen" fest, wie in der abbildung unten dargestellt.
Bearbeiten Sie die StoreManager\Index.cshtml-Ansicht , und entfernen Sie sie AlbumArtUrl
. AlbumArtUrl
Durch das Entfernen wird die Präsentation besser lesbar. Der fertige Code wird nachfolgend dargestellt.
@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>
Öffnen Sie die Datei "Controllers\StoreManagerController.cs ", und suchen Sie die Index
Methode. Fügen Sie die OrderBy
Klausel hinzu, damit die Alben nach Preis sortiert werden. Der vollständige Code wird unten angezeigt.
public ViewResult Index()
{
var albums = db.Albums.Include(a => a.Genre).Include(a => a.Artist)
.OrderBy(a => a.Price);
return View(albums.ToList());
}
Die Sortierung nach Preis erleichtert das Testen von Änderungen an der Datenbank. Wenn Sie die Bearbeitungs- und Erstellungsmethoden testen, können Sie einen niedrigen Preis verwenden, damit die gespeicherten Daten zuerst angezeigt werden.
Öffnen Sie die Datei "StoreManager\Edit.cshtml ". Fügen Sie die folgende Zeile direkt hinter dem Legendentag hinzu.
@Html.HiddenFor(model => model.AlbumId)
Der folgende Code zeigt den Kontext dieser Änderung:
@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. -->
}
Dies AlbumId
ist erforderlich, um Änderungen an einem Albumdatensatz vorzunehmen.
Drücken Sie STRG+F5, um die Anwendung auszuführen. Wählen Sie den Link "Administrator " aus, und wählen Sie dann den Link "Neu erstellen" aus, um ein neues Album zu erstellen. Überprüfen Sie, ob die Albuminformationen gespeichert wurden. Bearbeiten Sie ein Album, und überprüfen Sie, ob die von Ihnen vorgenommenen Änderungen beibehalten werden.
Das Albumschema
Der StoreManager
vom MVC-Gerüstmechanismus erstellte Controller ermöglicht CRUD -Zugriff (Erstellen, Lesen, Aktualisieren, Löschen) auf die Alben in der Musikspeicherdatenbank. Das Schema für Albuminformationen wird unten angezeigt:
Die Albums
Tabelle speichert das Albumgenre und die Beschreibung nicht, es speichert einen Fremdschlüssel für die Genres
Tabelle. Die Genres
Tabelle enthält den Genrenamen und die Beschreibung. Ebenso enthält die Albums
Tabelle nicht den Namen der Albumkünstler, sondern einen Fremdschlüssel für die Artists
Tabelle. Die Artists
Tabelle enthält den Namen des Künstlers. Wenn Sie die Daten in der Albums
Tabelle untersuchen, können Sie sehen, dass jede Zeile einen Fremdschlüssel für die Genres
Tabelle und einen Fremdschlüssel für die Artists
Tabelle enthält. Die folgende Abbildung zeigt einige Tabellendaten aus der Albums
Tabelle.
Das HTML-Auswahltag
Das HTML-Element (das vom HTML DropDownList-Hilfsprogramm <select>
erstellt wird) wird verwendet, um eine vollständige Liste von Werten anzuzeigen (z. B. die Liste der Genres). Bei Bearbeitungsformularen kann die Auswahlliste den aktuellen Wert anzeigen, wenn der aktuelle Wert bekannt ist. Wir haben dies zuvor gesehen, als wir den ausgewählten Wert auf Comedy festgelegt haben. Die Auswahlliste eignet sich ideal zum Anzeigen von Kategorie- oder Fremdschlüsseldaten. Das <select>
Element für den Fremdschlüssel "Genre" zeigt die Liste der möglichen Genrenamen an, aber wenn Sie das Format speichern, wird die Genre-Eigenschaft mit dem Fremdschlüsselwert "Genre" aktualisiert, nicht mit dem angezeigten Genrenamen. In der abbildung unten ist das Genre ausgewählt Disco und der Künstler ist Donna Summer.
Untersuchen des ASP.NET MVC-Gerüstcodes
Öffnen Sie die Datei "Controllers\StoreManagerController.cs ", und suchen Sie die HTTP GET Create
Methode.
public ActionResult Create()
{
ViewBag.GenreId = new SelectList(db.Genres, "GenreId", "Name");
ViewBag.ArtistId = new SelectList(db.Artists, "ArtistId", "Name");
return View();
}
Die Create
Methode fügt zwei SelectList-Objekte hinzu ViewBag
, eine, die die Genreinformationen enthalten soll, und eine, um die Künstlerinformationen zu enthalten. Die oben verwendete SelectList-Konstruktorüberladung verwendet drei Argumente:
public SelectList(
IEnumerable items,
string dataValueField,
string dataTextField
)
- items: An IEnumerable containing the items in the list. Im obigen Beispiel wird die Liste der von
db.Genres
. - dataValueField: Der Name der Eigenschaft in der Liste "IEnumerable" , die den Schlüsselwert enthält. Im obigen
GenreId
Beispiel undArtistId
. - dataTextField: Der Name der Eigenschaft in der Liste "IEnumerable ", die die anzuzeigenden Informationen enthält. Sowohl in der Künstler- als auch in der Genretabelle wird das
name
Feld verwendet.
Öffnen Sie die Datei Views\StoreManager\Create.cshtml , und überprüfen Sie das Html.DropDownList
Hilfsmarkup für das Genrefeld.
@model MvcMusicStore.Models.Album
@* Markup removed for clarity.*@
@Html.DropDownList("GenreId", String.Empty)
Die erste Zeile zeigt, dass die Erstellungsansicht ein Album
Modell verwendet. In der Create
oben gezeigten Methode wurde kein Modell übergeben, sodass die Ansicht ein NULL-Modell Album
erhält. An diesem Punkt erstellen wir ein neues Album, sodass wir keine Daten dafür haben Album
.
Die oben gezeigte Html.DropDownList-Überladung verwendet den Namen des Felds, das an das Modell gebunden werden soll. Außerdem wird dieser Name verwendet, um nach einem ViewBag-Objekt zu suchen, das ein SelectList-Objekt enthält. Bei Verwendung dieser Überladung müssen Sie das ViewBag SelectList -Objekt GenreId
benennen. Der zweite Parameter (String.Empty
) ist der Text, der angezeigt werden soll, wenn kein Element ausgewählt ist. Genau das wollen wir beim Erstellen eines neuen Albums. Wenn Sie den zweiten Parameter entfernt und den folgenden Code verwendet haben:
@Html.DropDownList("GenreId")
Die Auswahlliste würde standardmäßig das erste Element oder Rock in unserem Beispiel verwenden.
Untersuchen der HTTP POST Create
Methode.
//
// 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);
}
Diese Überladung der Create
Methode verwendet ein album
Objekt, das vom ASP.NET MVC-Modellbindungssystem aus den bereitgestellten Formularwerten erstellt wird. Wenn Sie ein neues Album übermitteln, wenn der Modellstatus gültig ist und keine Datenbankfehler vorhanden sind, wird das neue Album die Datenbank hinzugefügt. Die folgende Abbildung zeigt die Erstellung eines neuen Albums.
Mit dem Fiddler-Tool können Sie die geposteten Formularwerte untersuchen, die ASP.NET MVC-Modellbindung zum Erstellen des Albumobjekts verwendet.
.
Umgestalten der ViewBag SelectList-Erstellung
Sowohl die Edit
Methoden als auch die HTTP POST Create
Methode weisen identischen Code auf, um die SelectList im ViewBag einzurichten. Im Geiste von DRY werden wir diesen Code umgestalten. Wir verwenden diesen umgestalteten Code später.
Erstellen Sie eine neue Methode, um dem ViewBag ein Genre und einen Künstler SelectList hinzuzufügen.
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);
}
Ersetzen Sie die beiden Zeilen, die ViewBag
in jedem der Create
Methoden Edit
festgelegt werden, durch einen Aufruf der SetGenreArtistViewBag
Methode. Der fertige Code wird nachfolgend dargestellt.
//
// 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);
}
Erstellen Sie ein neues Album, und bearbeiten Sie ein Album, um die Änderungen zu überprüfen.
Explizites Übergeben der SelectList an die DropDownList
Die von der ASP.NET MVC-Gerüst erstellten Erstellungs- und Bearbeitungsansichten verwenden die folgende DropDownList-Überladung :
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"
)
Das DropDownList
Markup für die Erstellungsansicht wird unten angezeigt.
@Html.DropDownList("GenreId", String.Empty)
Da die ViewBag
Eigenschaft für den SelectList
Namen lautet GenreId
, verwendet das DropDownList-Hilfsprogramm die GenreId
SelectList im ViewBag. In der folgenden DropDownList-Überladung wird die SelectList
Explizite Übergeben.
public static MvcHtmlString DropDownList(
this HtmlHelper htmlHelper,
string name, // The name of the ViewModel property to bind.
IEnumerable selectList // The SelectList
)
Öffnen Sie die Datei Views\StoreManager\Edit.cshtml , und ändern Sie den DropDownList-Aufruf so, dass er explizit in die SelectList übergeben wird, indem Sie die oben genannte Überladung verwenden. Führen Sie dies für die Kategorie Genre aus. Der fertige Code wird unten angezeigt:
@Html.DropDownList("GenreId", ViewBag.GenreId as SelectList)
Führen Sie die Anwendung aus, und klicken Sie auf den Administratorlink , navigieren Sie dann zu einem Jazzalbum, und wählen Sie den Link "Bearbeiten" aus.
Anstatt Jazz als aktuell ausgewähltes Genre anzuzeigen, wird Rock angezeigt. Wenn das Zeichenfolgenargument (die zu bindende Eigenschaft) und das SelectList-Objekt denselben Namen haben, wird der ausgewählte Wert nicht verwendet. Wenn kein ausgewählter Wert angegeben wird, verwenden Browser standardmäßig das erste Element in der SelectList(dies ist Rock im obigen Beispiel). Dies ist eine bekannte Einschränkung des DropDownList-Hilfsprogramms .
Öffnen Sie die Datei "Controllers\StoreManagerController.cs ", und ändern Sie die SelectList-Objektnamen in Genres
und Artists
. Der fertige Code wird unten angezeigt:
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);
}
Die Namen Genres und Künstler sind bessere Namen für die Kategorien, da sie mehr als nur die ID jeder Kategorie enthalten. Die Umgestaltung, die wir zuvor geleistet haben, zahlten sich aus. Anstatt den ViewBag in vier Methoden zu ändern, wurden unsere Änderungen auf die SetGenreArtistViewBag
Methode isoliert.
Ändern Sie den DropDownList-Aufruf in den Erstellungs- und Bearbeitungsansichten, um die neuen SelectList-Namen zu verwenden. Das neue Markup für die Bearbeitungsansicht wird unten angezeigt:
<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>
Die Ansicht "Erstellen" erfordert eine leere Zeichenfolge, um zu verhindern, dass das erste Element in der SelectList angezeigt wird.
<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>
Erstellen Sie ein neues Album, und bearbeiten Sie ein Album, um die Änderungen zu überprüfen. Testen Sie den Bearbeitungscode, indem Sie ein Album mit einem anderen Genre als Rock auswählen.
Verwenden eines Ansichtsmodells mit dem DropDownList-Hilfsprogramm
Erstellen Sie eine neue Klasse im Ordner "ViewModels" mit dem Namen AlbumSelectListViewModel
. Ersetzen Sie den Code in der AlbumSelectListViewModel
Klasse durch Folgendes:
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);
}
}
}
Der AlbumSelectListViewModel
Konstruktor nimmt ein Album, eine Liste von Künstlern und Genres und erstellt ein Objekt, das das Album und eine SelectList
für Genres und Künstler enthält.
Erstellen Sie das Projekt so, dass das AlbumSelectListViewModel
Projekt verfügbar ist, wenn wir im nächsten Schritt eine Ansicht erstellen.
Fügen Sie der StoreManagerController
Methode eine EditVM
Methode hinzu. Der fertige Code wird nachfolgend dargestellt.
//
// 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);
}
Klicken Sie mit der rechten Maustaste auf AlbumSelectListViewModel
"Auflösen", und verwenden Sie dann MvcMusicStore.ViewModels;.
Alternativ können Sie die folgende Anweisung hinzufügen:
using MvcMusicStore.ViewModels;
Klicken Sie mit der rechten Maustaste, EditVM
und wählen Sie "Ansicht hinzufügen" aus. Verwenden Sie die unten gezeigten Optionen.
Wählen Sie "Hinzufügen" aus, und ersetzen Sie dann den Inhalt der Datei "Views\StoreManager\EditVM.cshtml" durch Folgendes:
@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>
Das EditVM
Markup ähnelt dem ursprünglichen Edit
Markup mit den folgenden Ausnahmen.
- Modelleigenschaften in der
Edit
Ansicht sind des Formularsmodel.property
(z. Bmodel.Title
. ). Modelleigenschaften in derEditVm
Ansicht sind des Formularsmodel.Album.property
(z. Bmodel.Album.Title
. ). Der Grund dafür ist, dass dieEditVM
Ansicht einen Container für einenAlbum
, nichtAlbum
wie in derEdit
Ansicht, übergeben wird. - Der zweite DropDownList-Parameter stammt aus dem Ansichtsmodell, nicht aus dem ViewBag.The DropDownList second parameter comes from the view model, not the ViewBag.
- Die BeginForm-Hilfsprogramm in der
EditVM
Ansicht sendet explizit zurück zurEdit
Aktionsmethode. Durch das Zurücksetzen auf dieEdit
Aktion müssen wir keine Aktion schreibenHTTP POST EditVM
und dieHTTP POST
Edit
Aktion wiederverwenden.
Führen Sie die Anwendung aus, und bearbeiten Sie ein Album. Ändern Sie die zu verwendende EditVM
URL. Ändern Sie ein Feld, und drücken Sie die Schaltfläche "Speichern ", um zu überprüfen, ob der Code funktioniert.
Welchen Ansatz sollten Sie verwenden?
Alle drei gezeigten Ansätze sind akzeptabel. Viele Entwickler bevorzugen es, die SelectList
Verwendung explizit an die DropDownList
ViewBag
Verwendung zu übergeben. Dieser Ansatz hat den zusätzlichen Vorteil, ihnen die Flexibilität zu geben, einen passenderen Namen für die Sammlung zu verwenden. Eine Einschränkung besteht darin, dass Sie das ViewBag SelectList
Objekt nicht mit demselben Namen wie die Modelleigenschaft benennen können.
Einige Entwickler bevorzugen den ViewModel-Ansatz. Andere betrachten das ausführlichere Markup und den generierten HTML-Code des ViewModel-Ansatzes als Nachteil.
In diesem Abschnitt haben wir drei Ansätze zur Verwendung von DropDownList mit Kategoriedaten kennengelernt. Im nächsten Abschnitt wird gezeigt, wie eine neue Kategorie hinzugefügt wird.