Memeriksa bagaimana ASP.NET MVC membuat perancah DropDownList Helper
oleh Rick Anderson
Di Penjelajah Solusi, klik kanan folder Pengontrol lalu pilih Tambahkan Pengontrol. Beri nama pengontrol StoreManagerController. Atur opsi untuk dialog Tambahkan Pengontrol seperti yang ditunjukkan pada gambar di bawah ini.
Edit tampilan StoreManager\Index.cshtml dan hapus AlbumArtUrl
. Menghapus AlbumArtUrl
akan membuat presentasi lebih mudah dibaca. Kode yang telah selesai ditunjukkan di bawah ini.
@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>
Buka file Controllers\StoreManagerController.cs dan temukan metode .Index
OrderBy
Tambahkan klausa sehingga album akan diurutkan berdasarkan harga. Kode lengkap ditunjukkan di bawah ini.
public ViewResult Index()
{
var albums = db.Albums.Include(a => a.Genre).Include(a => a.Artist)
.OrderBy(a => a.Price);
return View(albums.ToList());
}
Mengurutkan berdasarkan harga akan memudahkan pengujian perubahan pada database. Saat menguji metode edit dan buat, Anda dapat menggunakan harga rendah sehingga data yang disimpan akan muncul terlebih dahulu.
Buka file StoreManager\Edit.cshtml. Tambahkan baris berikut tepat setelah tag legenda.
@Html.HiddenFor(model => model.AlbumId)
Kode berikut menunjukkan konteks perubahan ini:
@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
diperlukan untuk membuat perubahan pada rekaman album.
Klik CTRL + F5 untuk menjalankan aplikasi. Pilih tautan Admin , lalu pilih tautan Buat Baru untuk membuat album baru. Verifikasi bahwa informasi album telah disimpan. Edit album dan verifikasi perubahan yang Anda buat dipertahankan.
Skema Album
StoreManager
Pengontrol yang dibuat oleh mekanisme perancah MVC memungkinkan akses CRUD (Buat, Baca, Perbarui, Hapus) ke album di database penyimpanan musik. Skema untuk informasi album ditunjukkan di bawah ini:
Tabel Albums
tidak menyimpan genre dan deskripsi album, tabel menyimpan kunci asing ke Genres
tabel. Tabel Genres
berisi nama dan deskripsi genre. Demikian juga, Albums
tabel tidak berisi nama artis album, tetapi kunci asing untuk Artists
tabel. Tabel Artists
berisi nama artis. Jika Anda memeriksa data dalam Albums
tabel, Anda dapat melihat setiap baris berisi kunci asing ke Genres
tabel dan kunci asing ke Artists
tabel. Gambar di bawah ini memperlihatkan beberapa data tabel dari Albums
tabel.
Tag Pilih HTML
Elemen HTML <select>
(dibuat oleh pembantu DropDownList HTML) digunakan untuk menampilkan daftar lengkap nilai (seperti daftar genre). Untuk formulir edit, saat nilai saat ini diketahui, daftar pilih dapat menampilkan nilai saat ini. Kami melihat ini sebelumnya ketika kami menetapkan nilai yang dipilih ke Comedy. Daftar pemilihan sangat ideal untuk menampilkan kategori atau data kunci asing. Elemen <select>
untuk kunci asing Genre menampilkan daftar kemungkinan nama genre, tetapi ketika Anda menyimpan formulir, properti Genre diperbarui dengan nilai kunci asing Genre, bukan nama genre yang ditampilkan. Pada gambar di bawah ini, genre yang dipilih adalah Disco dan artisnya adalah Donna Summer.
Memeriksa Kode Perancah MVC ASP.NET
Buka file Controllers\StoreManagerController.cs dan temukan metode .HTTP GET Create
public ActionResult Create()
{
ViewBag.GenreId = new SelectList(db.Genres, "GenreId", "Name");
ViewBag.ArtistId = new SelectList(db.Artists, "ArtistId", "Name");
return View();
}
Metode ini Create
menambahkan dua objek SelectList ke ViewBag
, satu untuk berisi informasi genre, dan satu untuk berisi informasi artis. Overload konstruktor SelectList yang digunakan di atas mengambil tiga argumen:
public SelectList(
IEnumerable items,
string dataValueField,
string dataTextField
)
- item: IEnumerable yang berisi item dalam daftar. Dalam contoh di atas, daftar genre yang dikembalikan oleh
db.Genres
. - dataValueField: Nama properti dalam daftar IEnumerable yang berisi nilai kunci. Dalam contoh di atas,
GenreId
danArtistId
. - dataTextField: Nama properti dalam daftar IEnumerable yang berisi informasi yang akan ditampilkan. Dalam artis dan tabel genre,
name
bidang digunakan.
Buka file Views\StoreManager\Create.cshtml dan periksa markup pembantu Html.DropDownList
untuk bidang genre.
@model MvcMusicStore.Models.Album
@* Markup removed for clarity.*@
@Html.DropDownList("GenreId", String.Empty)
Baris pertama menunjukkan bahwa tampilan buat mengambil Album
model. Dalam metode yang ditunjukkan Create
di atas, tidak ada model yang diteruskan, sehingga tampilan mendapatkan model nullAlbum
. Pada titik ini kami membuat album baru sehingga kami tidak memiliki data untuk Album
itu.
Overload Html.DropDownList yang ditunjukkan di atas mengambil nama bidang untuk mengikat model. Ini juga menggunakan nama ini untuk mencari objek ViewBag yang berisi objek SelectList . Dengan menggunakan kelebihan beban ini, Anda diharuskan untuk memberi nama objek GenreId
ViewBag SelectList . Parameter kedua (String.Empty
) adalah teks yang ditampilkan ketika tidak ada item yang dipilih. Inilah yang kita inginkan saat membuat album baru. Jika Anda menghapus parameter kedua dan menggunakan kode berikut:
@Html.DropDownList("GenreId")
Daftar pilihan akan default ke elemen pertama, atau Rock dalam sampel kami.
Memeriksa metode .HTTP POST Create
//
// 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);
}
Kelebihan metode Create
ini mengambil album
objek, yang dibuat oleh sistem pengikatan model MVC ASP.NET dari nilai formulir yang diposting. Saat Anda mengirimkan album baru, jika status model valid dan tidak ada kesalahan database, album baru ditambahkan database. Gambar berikut menunjukkan pembuatan album baru.
Anda dapat menggunakan alat fiddler untuk memeriksa nilai formulir yang diposting yang ASP.NET penggunaan pengikatan model MVC untuk membuat objek album.
.
Merefaktor Pembuatan Daftar Pilih ViewBag
Edit
Metode dan HTTP POST Create
metode memiliki kode yang identik untuk menyiapkan SelectList di ViewBag. Dalam semangat DRY, kita akan merefaktor kode ini. Kita akan menggunakan kode yang direfaktor ini nanti.
Buat metode baru untuk menambahkan genre dan artis SelectList ke 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);
}
Ganti dua baris yang mengatur ViewBag
di masing-masing Create
metode dan Edit
dengan panggilan ke SetGenreArtistViewBag
metode . Kode yang telah selesai ditunjukkan di bawah ini.
//
// 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);
}
Buat album baru dan edit album untuk memverifikasi perubahan yang berfungsi.
Secara Eksplisit Meneruskan SelectList ke DropDownList
Tampilan buat dan edit yang dibuat oleh perancah MVC ASP.NET menggunakan overload DropDownList berikut:
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"
)
DropDownList
Markup untuk tampilan buat ditunjukkan di bawah ini.
@Html.DropDownList("GenreId", String.Empty)
ViewBag
Karena properti untuk SelectList
diberi nama GenreId
, pembantu DropDownList akan menggunakan GenreId
SelectList di ViewBag. Dalam overload DropDownList berikut, SelectList
secara eksplisit diteruskan.
public static MvcHtmlString DropDownList(
this HtmlHelper htmlHelper,
string name, // The name of the ViewModel property to bind.
IEnumerable selectList // The SelectList
)
Buka file Views\StoreManager\Edit.cshtml, dan ubah panggilan DropDownList untuk secara eksplisit meneruskan SelectList, menggunakan kelebihan beban di atas. Lakukan ini untuk kategori Genre. Kode yang telah selesai ditunjukkan di bawah ini:
@Html.DropDownList("GenreId", ViewBag.GenreId as SelectList)
Jalankan aplikasi dan klik tautan Admin , lalu navigasikan ke album Jazz dan pilih tautan Edit .
Alih-alih menampilkan Jazz sebagai genre yang saat ini dipilih, Rock ditampilkan. Ketika argumen string (properti untuk mengikat) dan objek SelectList memiliki nama yang sama, nilai yang dipilih tidak digunakan. Ketika tidak ada nilai yang dipilih yang disediakan, browser default ke elemen pertama dalam SelectList(yang merupakan Rock dalam contoh di atas). Ini adalah batasan yang diketahui dari pembantu DropDownList .
Buka file Controllers\StoreManagerController.cs dan ubah nama objek SelectList menjadi Genres
dan Artists
. Kode yang telah selesai ditunjukkan di bawah ini:
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);
}
Nama Genre dan Artis adalah nama yang lebih baik untuk kategori, karena berisi lebih dari sekadar ID dari setiap kategori. Pemfaktoran ulang yang kami lakukan sebelumnya terbayar. Alih-alih mengubah ViewBag dalam empat metode, perubahan kami diisolasi ke SetGenreArtistViewBag
metode .
Ubah panggilan DropDownList di tampilan buat dan edit untuk menggunakan nama SelectList baru. Markup baru untuk tampilan edit ditunjukkan di bawah ini:
<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>
Tampilan Buat memerlukan string kosong untuk mencegah item pertama dalam SelectList ditampilkan.
<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>
Buat album baru dan edit album untuk memverifikasi perubahan yang berfungsi. Uji kode edit dengan memilih album dengan genre selain Rock.
Menggunakan Model Tampilan dengan Pembantu DropDownList
Buat kelas baru di folder ViewModels bernama AlbumSelectListViewModel
. Ganti kode di AlbumSelectListViewModel
kelas dengan yang berikut:
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
mengambil album, daftar artis dan genre dan membuat objek yang berisi album dan SelectList
untuk genre dan artis.
Bangun proyek sehingga AlbumSelectListViewModel
tersedia saat kita membuat tampilan di langkah berikutnya.
EditVM
Tambahkan metode ke StoreManagerController
. Kode yang telah selesai ditunjukkan di bawah ini.
//
// 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);
}
AlbumSelectListViewModel
Klik kanan , pilih Atasi, lalu gunakan MvcMusicStore.ViewModels;.
Atau, Anda dapat menambahkan pernyataan penggunaan berikut:
using MvcMusicStore.ViewModels;
EditVM
Klik kanan dan pilih Tambahkan Tampilan. Gunakan opsi yang ditunjukkan di bawah ini.
Pilih Tambahkan, lalu ganti konten file Views\StoreManager\EditVM.cshtml dengan yang berikut ini:
@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>
EditVM
Markup sangat mirip dengan markup asli Edit
dengan pengecualian berikut.
- Properti model
Edit
dalam tampilan adalah formulirmodel.property
(misalnya,model.Title
). Properti modelEditVm
dalam tampilan adalah formulirmodel.Album.property
(misalnya,model.Album.Title
). Itu karenaEditVM
tampilan diteruskan kontainer untukAlbum
, bukanAlbum
sebagai dalamEdit
tampilan. - Parameter kedua DropDownList berasal dari model tampilan, bukan ViewBag.
- Pembantu BeginForm dalam
EditVM
tampilan secara eksplisit memposting kembali keEdit
metode tindakan. Dengan memposting kembali keEdit
tindakan, kita tidak perlu menulisHTTP POST EditVM
tindakan dan dapat menggunakan kembali tindakan.HTTP POST
Edit
Jalankan aplikasi dan edit album. Ubah URL untuk menggunakan EditVM
. Ubah bidang dan tekan tombol Simpan untuk memverifikasi kode berfungsi.
Pendekatan mana yang harus Anda gunakan?
Ketiga pendekatan yang ditampilkan dapat diterima. Banyak pengembang lebih suka secara eksplisit meneruskan SelectList
ke DropDownList
menggunakan ViewBag
. Pendekatan ini memiliki keuntungan tambahan untuk memberi Anda fleksibilitas menggunakan nama yang lebih sesuai untuk koleksi. Satu peringatan adalah Anda tidak dapat memberi nama ViewBag SelectList
objek dengan nama yang sama dengan properti model.
Beberapa pengembang lebih suka pendekatan ViewModel. Yang lain menganggap markup yang lebih verbose dan HTML yang dihasilkan dari pendekatan ViewModel merugikan.
Di bagian ini kita telah mempelajari tiga pendekatan untuk menggunakan DropDownList dengan data kategori. Di bagian berikutnya, kita akan menunjukkan cara menambahkan kategori baru.