Zkoumání, jak ASP.NET MVC vygeneruje uživatelské rozhraní pomocné rutiny DropDownList
V Průzkumník řešení klikněte pravým tlačítkem myši na složku Kontrolery a pak vyberte Přidat kontroler. Pojmenujte řadič StoreManagerController. Nastavte možnosti dialogového okna Přidat kontroler , jak je znázorněno na obrázku níže.
Upravte zobrazení StoreManager\Index.cshtml a odeberte AlbumArtUrl
. Odebráním AlbumArtUrl
bude prezentace čitelnější. Dokončený kód je uvedený níže.
@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>
Otevřete soubor Controllers\StoreManagerController.cs a vyhledejte metoduIndex
. Přidejte klauzuli OrderBy
, aby alba byla seřazena podle ceny. Kompletní kód je uvedený níže.
public ViewResult Index()
{
var albums = db.Albums.Include(a => a.Genre).Include(a => a.Artist)
.OrderBy(a => a.Price);
return View(albums.ToList());
}
Řazení podle ceny usnadní testování změn v databázi. Při testování metod úprav a vytváření můžete použít nízkou cenu, aby se uložená data zobrazovala jako první.
Otevřete soubor StoreManager\Edit.cshtml. Přidejte následující řádek těsně za značku legendy.
@Html.HiddenFor(model => model.AlbumId)
Následující kód ukazuje kontext této změny:
@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. -->
}
Je AlbumId
nutné provést změny v záznamu alba.
Stiskněte klávesy CTRL+F5 a spusťte aplikaci. Vyberte odkaz Správce a pak výběrem odkazu Vytvořit nový vytvořte nové album. Ověřte, že byly uloženy informace o albu. Upravte album a ověřte, že provedené změny jsou trvalé.
Schéma alba
StoreManager
Kontroler vytvořený mechanismem generování uživatelského rozhraní MVC umožňuje CRUD (Create, Read, Update, Delete) přístup k albům v databázi úložiště hudby. Schéma informací o albu je znázorněno níže:
Tabulka Albums
neukládá žánr a popis alba, ukládá cizí klíč do Genres
tabulky. Tabulka Genres
obsahuje název a popis žánru. Albums
Stejně tak tabulka neobsahuje název umělce alba, ale cizí klíč tabulkyArtists
. Tabulka Artists
obsahuje jméno autora. Pokud prozkoumáte data v Albums
tabulce, můžete vidět, že každý řádek obsahuje cizí klíč tabulky Genres
a cizí klíč tabulky Artists
. Na následujícím obrázku jsou některá data tabulky z Albums
tabulky.
Značka Pro výběr HTML
Element HTML <select>
(vytvořený pomocným rutinou HTML DropDownList ) slouží k zobrazení kompletního seznamu hodnot (například seznam žánrů). Při úpravách formulářů, pokud je aktuální hodnota známá, může seznam výběru zobrazit aktuální hodnotu. Viděli jsme to dříve, když jsme nastavili vybranou hodnotu na Comedy. Seznam výběrů je ideální pro zobrazení dat kategorie nebo cizího klíče. Prvek <select>
cizího klíče Žánr zobrazuje seznam možných názvů žánrů, ale když uložíte formulář Žánr vlastnost se aktualizuje hodnotou cizího klíče Žánr, nikoli zobrazovaný název žánru. Na obrázku níže je žánr vybraný Disko a umělec je Donna Summer.
Prozkoumání kódu vygenerovaného uživatelského rozhraní MVC ASP.NET
Otevřete soubor Controllers\StoreManagerController.cs a vyhledejte metoduHTTP GET Create
.
public ActionResult Create()
{
ViewBag.GenreId = new SelectList(db.Genres, "GenreId", "Name");
ViewBag.ArtistId = new SelectList(db.Artists, "ArtistId", "Name");
return View();
}
Metoda Create
přidá dva SelectList objekty do ViewBag
, jeden obsahovat informace o žánru, a jeden, který bude obsahovat informace interpreta. Přetížení konstruktoru SelectList použité výše přebírá tři argumenty:
public SelectList(
IEnumerable items,
string dataValueField,
string dataTextField
)
- items: IEnumerable obsahující položky v seznamu. V předchozím příkladu seznam žánrů vrácených
db.Genres
. - dataValueField: Název vlastnosti v seznamu IEnumerable , který obsahuje hodnotu klíče. V příkladu výše
GenreId
aArtistId
. - dataTextField: Název vlastnosti v seznamu IEnumerable , který obsahuje informace k zobrazení. V tabulce umělců i žánrů se
name
pole používá.
Otevřete soubor Views\StoreManager\Create.cshtml a prozkoumejte Html.DropDownList
pomocné značky pro pole žánru.
@model MvcMusicStore.Models.Album
@* Markup removed for clarity.*@
@Html.DropDownList("GenreId", String.Empty)
První řádek ukazuje, že zobrazení pro vytvoření používá Album
model. Create
Ve výše uvedené metodě nebyl předán žádný model, takže zobrazení získá model s hodnotou nullAlbum
. V tuto chvíli vytváříme nové album, takže pro něj nemáme žádná Album
data.
Přetížení Html.DropDownList zobrazené výše přebírá název pole, které se má svázat s modelem. Tento název také používá k vyhledání objektu ViewBag obsahující objekt SelectList . Pomocí tohoto přetížení je nutné pojmenovat ViewBag SelectList objekt GenreId
. Druhý parametr (String.Empty
) je text, který se má zobrazit, když není vybrána žádná položka. To je přesně to, co chceme při vytváření nového alba. Pokud jste odebrali druhý parametr a použili následující kód:
@Html.DropDownList("GenreId")
Výběrový seznam by ve výchozím nastavení byl první prvek nebo Rock v naší ukázce.
HTTP POST Create
Zkoumání metody.
//
// 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);
}
Toto přetížení Create
metody přebírá album
objekt vytvořený systémem vazby modelu ASP.NET MVC z publikovaných hodnot formuláře. Když odešlete nové album, pokud je stav modelu platný a nedojde k žádným chybám databáze, přidá se nové album do databáze. Následující obrázek znázorňuje vytvoření nového alba.
Nástroj fiddler můžete použít k prozkoumání odeslaných hodnot formuláře, které ASP.NET vazby modelu MVC používá k vytvoření objektu alba.
.
Refaktoring vytvoření selectlistu ViewBag
Metody Edit
i HTTP POST Create
metoda mají identický kód pro nastavení SelectList v ViewBag. V duchu DRY budeme refaktorovat tento kód. Tento refaktorovaný kód použijeme později.
Vytvořte novou metodu pro přidání žánru a interpreta SelectList do 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);
}
Nahraďte dva řádky, které nastaví ViewBag
v jednotlivých metodách Create
Edit
, voláním SetGenreArtistViewBag
metody. Dokončený kód je uvedený níže.
//
// 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);
}
Vytvořte nové album a upravte album, abyste ověřili, že změny fungují.
Explicitní předání seznamu SelectList do rozevíracího seznamu
Při vytváření a úpravách zobrazení vytvořených generováním ASP.NET MVC se používá následující přetížení DropDownList :
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"
)
Kód DropDownList
pro zobrazení pro vytvoření je uvedený níže.
@Html.DropDownList("GenreId", String.Empty)
ViewBag
Protože vlastnost pro název SelectList
GenreId
, DropDownList pomocník bude používatGenreId
SelectList v ViewBag. V následujícím dropDownList přetížení je SelectList
explicitně předán.
public static MvcHtmlString DropDownList(
this HtmlHelper htmlHelper,
string name, // The name of the ViewModel property to bind.
IEnumerable selectList // The SelectList
)
Otevřete soubor Views\StoreManager\Edit.cshtml a změňte volání DropDownList explicitně předat SelectList pomocí přetížení výše. Udělejte to pro kategorii Žánr. Dokončený kód je uvedený níže:
@Html.DropDownList("GenreId", ViewBag.GenreId as SelectList)
Spusťte aplikaci a klikněte na odkaz Správce , přejděte do alba Jazz a vyberte odkaz Upravit .
Místo zobrazení Jazzu jako aktuálně vybraného žánru se zobrazí Rock. Pokud řetězcový argument (vlastnost vytvořit vazbu) a selectList objekt mají stejný název, vybraná hodnota se nepoužije. Pokud není k dispozici žádná vybraná hodnota, prohlížeče ve výchozím nastavení první prvek v SelectList(což je Rock v příkladu výše). Toto je známé omezení pomocné rutiny DropDownList .
Otevřete soubor Controllers\StoreManagerController.cs a změňte názvy objektů SelectList na Genres
a Artists
. Dokončený kód je uvedený níže:
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);
}
Názvy Žánry a umělci jsou lepšími názvy kategorií, protože obsahují více než jen ID každé kategorie. Refaktoring, který jsme udělali dříve, se vyplatil. Místo změny ViewBagu ve čtyřech metodách byly naše změny izolované pro metoduSetGenreArtistViewBag
.
Změňte volání DropDownList v zobrazení pro vytvoření a úpravu tak, aby používaly nové názvy SelectList. Nový kód pro zobrazení pro úpravy je zobrazený níže:
<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>
Zobrazení Vytvořit vyžaduje prázdný řetězec, aby se zabránilo zobrazení první položky v seznamu 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>
Vytvořte nové album a upravte album, abyste ověřili, že změny fungují. Otestujte kód úprav tak, že vyberete album s jiným žánrem než Rock.
Použití modelu zobrazení s pomocným nástrojem DropDownList
Vytvořte novou třídu ve složce ViewModels s názvem AlbumSelectListViewModel
. Nahraďte kód ve AlbumSelectListViewModel
třídě následujícím kódem:
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);
}
}
}
Konstruktor AlbumSelectListViewModel
vezme album, seznam umělců a žánrů a vytvoří objekt obsahující album a SelectList
žánry a umělce.
Sestavte projekt tak, aby AlbumSelectListViewModel
byl k dispozici při vytváření zobrazení v dalším kroku.
Přidejte metodu EditVM
do objektu StoreManagerController
. Dokončený kód je uvedený níže.
//
// 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);
}
Klikněte pravým tlačítkem myši , vyberte Přeložit a pak použijte MvcMusicStore.ViewModels;.AlbumSelectListViewModel
Alternativně můžete přidat následující příkaz using:
using MvcMusicStore.ViewModels;
Klikněte pravým tlačítkem myši EditVM
a vyberte Přidat zobrazení. Použijte níže uvedené možnosti.
Vyberte Přidat a pak nahraďte obsah souboru Views\StoreManager\EditVM.cshtml následujícím kódem:
@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>
Kód EditVM
je velmi podobný původnímu Edit
kódu s následujícími výjimkami.
- Vlastnosti modelu v
Edit
zobrazení jsou ve formulářimodel.property
(napříkladmodel.Title
). Vlastnosti modelu vEditVm
zobrazení jsou ve formulářimodel.Album.property
(napříkladmodel.Album.Title
). Je to proto, žeEditVM
zobrazení se předává kontejneru pro objektAlbum
, nikoli jakoAlbum
vEdit
zobrazení. - Druhý parametr DropDownList pochází z modelu zobrazení, nikoli ViewBag.
- Pomocná rutina BeginForm v
EditVM
zobrazení explicitně publikuje zpět doEdit
metody akce. Odesláním zpět naEdit
akci nemusíme napsatHTTP POST EditVM
akci a akci znovu použítHTTP POST
Edit
.
Spusťte aplikaci a upravte album. Změňte adresu URL tak, aby používala EditVM
. Změňte pole a stisknutím tlačítka Uložit ověřte, že kód funguje.
Jaký přístup byste měli použít?
Všechny tři zobrazené přístupy jsou přijatelné. Mnoho vývojářů dává přednost tomu, aby explicitně předalo SelectList
DropDownList
použití ViewBag
. Díky tomuto přístupu získáte větší flexibilitu při používání vhodnějšího názvu kolekce. Jedním upozorněním je, že objekt nemůže pojmenovat ViewBag SelectList
stejný název jako vlastnost modelu.
Někteří vývojáři dávají přednost přístupu ViewModel. Ostatní považují za nevýhodu více podrobných značek a vygenerovaný kód HTML modelu ViewModel.
V této části jsme se naučili tři přístupy k používání rozevíracího seznamu s daty kategorií. V další části si ukážeme, jak přidat novou kategorii.