Nuta
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Autor: Rick Anderson
W Eksplorator rozwiązań kliknij prawym przyciskiem myszy folder Controllers, a następnie wybierz polecenie Dodaj kontroler. Nadaj kontrolerowi nazwę StoreManagerController. Ustaw opcje okna dialogowego Dodawanie kontrolera , jak pokazano na poniższej ilustracji.

Edytuj widok StoreManager\Index.cshtml i usuń polecenie AlbumArtUrl. Usunięcie AlbumArtUrl spowoduje, że prezentacja będzie bardziej czytelna. Ukończony kod jest pokazany poniżej.
@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>
Otwórz plik Controllers\StoreManagerController.cs i znajdź metodę Index . Dodaj klauzulę , OrderBy aby albumy zostały posortowane według ceny. Pełny kod jest pokazany poniżej.
public ViewResult Index()
{
var albums = db.Albums.Include(a => a.Genre).Include(a => a.Artist)
.OrderBy(a => a.Price);
return View(albums.ToList());
}
Sortowanie według ceny ułatwi testowanie zmian w bazie danych. Podczas testowania metod edycji i tworzenia można użyć niskiej ceny, aby zapisane dane pojawiły się jako pierwsze.
Otwórz plik StoreManager\Edit.cshtml. Dodaj następujący wiersz tuż po tagu legendy.
@Html.HiddenFor(model => model.AlbumId)
Poniższy kod przedstawia kontekst tej zmiany:
@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. -->
}
Wymagane AlbumId jest wprowadzenie zmian w rekordzie albumu.
Naciśnij klawisze CTRL+F5, aby uruchomić aplikację. Wybierz link Administrator, a następnie wybierz link Utwórz nowy, aby utworzyć nowy album. Sprawdź, czy informacje o albumie zostały zapisane. Edytuj album i sprawdź, czy wprowadzone zmiany są utrwalane.
Schemat albumu
Kontroler StoreManager utworzony przez mechanizm tworzenia szkieletów MVC umożliwia dostęp CRUD (Create, Read, Update, Delete) do albumów w bazie danych sklepu muzycznego. Schemat informacji o albumie jest pokazany poniżej:

Tabela Albums nie przechowuje gatunku albumu i opisu, przechowuje klucz obcy do Genres tabeli. Tabela Genres zawiera nazwę gatunku i opis. Albums Podobnie tabela nie zawiera nazwy artystów albumów, ale klucza obcego do Artists tabeli. Tabela Artists zawiera nazwę artysty. Jeśli zbadasz dane w Albums tabeli, zobaczysz, że każdy wiersz zawiera klucz Genres obcy do tabeli i klucz obcy w Artists tabeli. Na poniższej ilustracji Albums przedstawiono niektóre dane tabeli z tabeli.

The HTML Select Tag
Element HTML <select> (utworzony przez pomocnik HTML DropDownList ) służy do wyświetlania pełnej listy wartości (takich jak lista gatunków). W przypadku formularzy edycji, gdy bieżąca wartość jest znana, lista wyboru może wyświetlić bieżącą wartość. Widzieliśmy to wcześniej, gdy ustawiliśmy wybraną wartość na Comedy. Lista wyboru jest idealna do wyświetlania danych kategorii lub klucza obcego. Element <select> klucza obcego gatunku wyświetla listę możliwych nazw gatunków, ale po zapisaniu formularza właściwość Gatunek zostanie zaktualizowana o wartość klucza obcego gatunku, a nie wyświetlaną nazwę gatunku. Na poniższej ilustracji wybrany gatunek to Disco , a artysta jest Donna Summer.

Badanie kodu szkieletowego ASP.NET MVC
Otwórz plik Controllers\StoreManagerController.cs i znajdź metodę HTTP 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 dodaje dwa obiekty SelectList do obiektu , które zawierają informacje o gatunku ViewBag, i jeden zawierający informacje o wykonawcy. Powyższe przeciążenie konstruktora SelectList przyjmuje trzy argumenty:
public SelectList(
IEnumerable items,
string dataValueField,
string dataTextField
)
- items: element IEnumerable zawierający elementy na liście. W powyższym przykładzie lista gatunków zwracanych przez
db.Genreselement . - dataValueField: nazwa właściwości na liście IEnumerable zawierająca wartość klucza. W powyższym
GenreIdprzykładzie iArtistId. - dataTextField: nazwa właściwości na liście IEnumerable zawierająca informacje do wyświetlenia. W tabeli
nameartystów i gatunku używane jest pole.
Otwórz plik Views\StoreManager\Create.cshtml i sprawdź Html.DropDownList znacznik pomocnika dla pola gatunku.
@model MvcMusicStore.Models.Album
@* Markup removed for clarity.*@
@Html.DropDownList("GenreId", String.Empty)
Pierwszy wiersz pokazuje, że widok tworzenia przyjmuje Album model. W metodzie pokazanej Create powyżej nie przekazano żadnego modelu, więc widok pobiera model o wartości nullAlbum. W tym momencie tworzymy nowy album, więc nie mamy dla niego żadnych Album danych.
Przeciążenie Html.DropDownList pokazane powyżej przyjmuje nazwę pola, które ma być powiązane z modelem. Używa również tej nazwy do wyszukiwania obiektu ViewBag zawierającego obiekt SelectList . Za pomocą tego przeciążenia należy nazwać obiekt GenreIdViewBag SelectList . Drugi parametr (String.Empty) to tekst do wyświetlenia, gdy nie wybrano żadnego elementu. Jest to dokładnie to, czego chcemy podczas tworzenia nowego albumu. Jeśli drugi parametr został usunięty i użyto następującego kodu:
@Html.DropDownList("GenreId")
Lista wyboru jest domyślnie ustawiona na pierwszy element lub Rock w naszym przykładzie.

HTTP POST Create Badanie 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);
}
To przeciążenie Create metody przyjmuje album obiekt utworzony przez system powiązania modelu MVC ASP.NET z opublikowanych wartości formularza. Po przesłaniu nowego albumu, jeśli stan modelu jest prawidłowy i nie ma błędów bazy danych, nowy album zostanie dodany do bazy danych. Na poniższej ilustracji przedstawiono tworzenie nowego albumu.

Za pomocą narzędzia fiddler można sprawdzić opublikowane wartości formularzy, które ASP.NET powiązania modelu MVC używane do tworzenia obiektu albumu.
.
Refaktoryzacja tworzenia elementu ViewBag SelectList
Edit Zarówno metody, jak i HTTP POST Create metoda mają identyczny kod, aby skonfigurować selectList w ViewBag. W duchu DRY refaktoryzujemy ten kod. Użyjemy tego refaktoryzowanego kodu później.
Utwórz nową metodę, aby dodać gatunek i artystę SelectList do elementu 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);
}
Zastąp dwa wiersze ustawieniem ViewBag w każdej z Create metod i Edit wywołaniem SetGenreArtistViewBag metody . Ukończony kod jest pokazany poniżej.
//
// 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);
}
Utwórz nowy album i edytuj album, aby sprawdzić, czy zmiany działają.
Jawne przekazywanie listy SelectList do listy rozwijanej
Tworzenie i edytowanie widoków utworzonych przez szkielet ASP.NET MVC używa następującego przeciążenia 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"
)
Poniżej DropDownList przedstawiono znaczniki dla widoku tworzenia.
@Html.DropDownList("GenreId", String.Empty)
ViewBag Ponieważ właściwość obiektu SelectList ma nazwę GenreId, pomocnik DropDownList użyjeGenreId kontrolki SelectList w obiekcie ViewBag. W poniższym przeciążeniu SelectList DropDownList parametr jest jawnie przekazywany.
public static MvcHtmlString DropDownList(
this HtmlHelper htmlHelper,
string name, // The name of the ViewModel property to bind.
IEnumerable selectList // The SelectList
)
Otwórz plik Views\StoreManager\Edit.cshtml i zmień wywołanie DropDownList, aby jawnie przekazać element SelectList przy użyciu przeciążenia powyżej. Zrób to dla kategorii Gatunek. Ukończony kod jest pokazany poniżej:
@Html.DropDownList("GenreId", ViewBag.GenreId as SelectList)
Uruchom aplikację i kliknij link Administrator , a następnie przejdź do albumu Jazz i wybierz link Edytuj .

Zamiast pokazywać Jazz jako aktualnie wybrany gatunek, rock jest wyświetlany. Gdy argument ciągu (właściwość do powiązania) i obiekt SelectList mają taką samą nazwę, wybrana wartość nie jest używana. Jeśli nie jest podana żadna wybrana wartość, przeglądarki są domyślne dla pierwszego elementu w elemecie SelectList (czyli Rock w powyższym przykładzie). Jest to znane ograniczenie pomocnika DropDownList .
Otwórz plik Controllers\StoreManagerController.cs i zmień nazwy obiektów SelectList na Genres i Artists. Ukończony kod jest pokazany poniżej:
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);
}
Nazwy Gatunek i Artyści są lepszymi nazwami kategorii, ponieważ zawierają więcej niż tylko identyfikator każdej kategorii. Refaktoryzacja, którą wcześniej opłaciliśmy. Zamiast zmieniać element ViewBag w czterech metodach, nasze zmiany zostały odizolowane od SetGenreArtistViewBag metody .
Zmień wywołanie DropDownList w widokach tworzenia i edytowania, aby używać nowych nazw SelectList . Nowy znacznik dla widoku edycji jest pokazany poniżej:
<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>
Widok Tworzenie wymaga pustego ciągu, aby zapobiec wyświetlaniu pierwszego elementu na liście 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>
Utwórz nowy album i edytuj album, aby sprawdzić, czy zmiany działają. Przetestuj kod edycji, wybierając album z gatunkiem innym niż Rock.
Używanie modelu widoku z pomocnikiem DropDownList
Utwórz nową klasę w folderze ViewModels o nazwie AlbumSelectListViewModel. Zastąp kod w AlbumSelectListViewModel klasie następującym kodem:
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 przyjmuje album, listę artystów i gatunków i tworzy obiekt zawierający album oraz SelectList obiekt dla gatunków i artystów.
Skompiluj projekt, AlbumSelectListViewModel aby był dostępny podczas tworzenia widoku w następnym kroku.
Dodaj metodę EditVM do metody StoreManagerController. Ukończony kod jest pokazany poniżej.
//
// 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);
}
Kliknij prawym przyciskiem myszy AlbumSelectListViewModel, wybierz pozycję Rozwiąż, a następnie użyj mvcMusicStore.ViewModels;.

Alternatywnie możesz dodać następującą instrukcję using:
using MvcMusicStore.ViewModels;
Kliknij prawym przyciskiem myszy EditVM i wybierz polecenie Dodaj widok. Użyj opcji przedstawionych poniżej.

Wybierz pozycję Dodaj, a następnie zastąp zawartość pliku Views\StoreManager\EditVM.cshtml następującym kodem:
@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>
Znaczniki EditVM są bardzo podobne do oryginalnego Edit adiustacji z następującymi wyjątkami.
- Właściwości modelu w
Editwidoku mają postaćmodel.property(na przykładmodel.Title). Właściwości modelu wEditVmwidoku mają postaćmodel.Album.property(na przykładmodel.Album.Title). Dzieje się tak, ponieważEditVMwidok jest przekazywany do kontenera dlaAlbumelementu , a nieAlbumjako wEditwidoku. - Drugi parametr DropDownList pochodzi z modelu widoku, a nie viewBag.
- Pomocnik BeginForm w
EditVMwidoku jawnie publikuje dane z powrotem doEditmetody akcji. Publikując z powrotem doEditakcji, nie musimy pisaćHTTP POST EditVMakcji i możemy ponownie użyćHTTP POSTEditakcji.
Uruchom aplikację i edytuj album. Zmień adres URL, aby używał polecenia EditVM. Zmień pole i naciśnij przycisk Zapisz, aby sprawdzić, czy kod działa.

Którego podejścia należy użyć?
Wszystkie trzy pokazane podejścia są dopuszczalne. Wielu deweloperów woli jawnie przekazać element SelectList do DropDownList metody przy użyciu polecenia ViewBag. Takie podejście ma dodatkową zaletę zapewniania elastyczności używania bardziej odpowiedniej nazwy dla kolekcji. Jednym z zastrzeżeń jest to, że nie można nazwać ViewBag SelectList obiektu o tej samej nazwie co właściwość modelu.
Niektórzy deweloperzy preferują podejście ViewModel. Inni uważają, że bardziej pełne znaczniki i wygenerowany kod HTML modelu ViewModel jest wadą.
W tej sekcji przedstawiono trzy podejścia do używania listy DropDownList z danymi kategorii. W następnej sekcji pokażemy, jak dodać nową kategorię.