Bagikan melalui


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.

Gambar kotak dialog Tambahkan Pengontrol Penjelajah Solusi

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:

Gambar skema Album

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.

Gambar beberapa data dari tabel Album

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.

Gambar genre yang dipilih Disko

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

)
  1. item: IEnumerable yang berisi item dalam daftar. Dalam contoh di atas, daftar genre yang dikembalikan oleh db.Genres.
  2. dataValueField: Nama properti dalam daftar IEnumerable yang berisi nilai kunci. Dalam contoh di atas, GenreId dan ArtistId.
  3. 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 GenreIdViewBag 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.

Gambar elemen pertama default

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.

Gambar yang 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.

Gambar alat Fiddler.

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 GenreIdSelectList 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 .

Gambar pilihan album Jazz untuk diedit

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);

}

AlbumSelectListViewModelKlik kanan , pilih Atasi, lalu gunakan MvcMusicStore.ViewModels;.

Pemilihan gambar mengatasi

Atau, Anda dapat menambahkan pernyataan penggunaan berikut:

using MvcMusicStore.ViewModels;

EditVM Klik kanan dan pilih Tambahkan Tampilan. Gunakan opsi yang ditunjukkan di bawah ini.

Gambar memperlihatkan dialog Tambahkan Tampilan

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 formulir model.property(misalnya, model.Title ). Properti model EditVm dalam tampilan adalah formulir model.Album.property(misalnya, model.Album.Title). Itu karena EditVM tampilan diteruskan kontainer untuk Album, bukan Album sebagai dalam Edit tampilan.
  • Parameter kedua DropDownList berasal dari model tampilan, bukan ViewBag.
  • Pembantu BeginForm dalam EditVM tampilan secara eksplisit memposting kembali ke Edit metode tindakan. Dengan memposting kembali ke Edit tindakan, kita tidak perlu menulis HTTP 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.

Gambar dengan U R L berubah menjadi Edit V M

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.