Sdílet prostřednictvím


Zkoumání, jak ASP.NET MVC vygeneruje pomocnou rutinu DropDownList

Rick Anderson

V Průzkumník řešení klikněte pravým tlačítkem na složku Controllers (Kontrolery) a pak vyberte Add Controller (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.

Obrázek dialogového okna Přidat kontroler Průzkumník řešení

Upravte zobrazení StoreManager\Index.cshtml a odeberte AlbumArtUrl. Odebráním AlbumArtUrl bude prezentace čitelnější. Dokončený kód je zobrazený 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 najděte metodu Index . Přidejte klauzuli OrderBy , aby se alba seřadila 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 zobrazila jako první.

Otevřete soubor StoreManager\Edit.cshtml . Následující řádek přidejte hned 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 potřeba k provedení změn záznamu alba.

Stiskněte klávesy CTRL+F5 a spusťte aplikaci. Vyberte odkaz Správa a pak výběrem odkazu Vytvořit nové vytvořte nové album. Ověřte, že se informace o albu uložily. Upravte album a ověřte, že se změny, které jste udělali, zachovaly.

Schéma alba

Kontroler StoreManager vytvořený mechanismem generování uživatelského rozhraní MVC umožňuje CRUD (Vytvořit, Číst, Aktualizovat, Odstranit) přístup k albům v databázi úložiště hudby. Schéma pro informace o albu je zobrazeno níže:

Obrázek schématu Alba

Tabulka Albums neukládá žánr a popis alba, ale cizí klíč k Genres tabulce. Tabulka Genres obsahuje název a popis žánru. Tabulka také Albums neobsahuje jméno interpretů alba, ale cizí klíč k tabulce Artists . Tabulka Artists obsahuje jméno umělce. Když prozkoumáte data v Albums tabulce, uvidíte, že každý řádek obsahuje cizí klíč k Genres tabulce a cizí klíč k Artists tabulce. Na obrázku níže jsou některá data tabulky z Albums tabulky.

Obrázek dat z tabulky Alba

Značka HTML Select

Element HTML <select> (vytvořený pomocným pomocníkem HTML DropDownList ) se používá k zobrazení úplného seznamu hodnot (například seznam žánrů). Pokud je u formulářů pro úpravy známá aktuální hodnota, může seznam výběrů 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 o kategoriích nebo cizích klíčích. Prvek <select> cizího klíče Žánr zobrazí seznam možných názvů žánrů, ale když uložíte formulář, vlastnost Žánr se aktualizuje hodnotou cizího klíče Žánr, nikoli zobrazovaným názvem žánru. Na obrázku níže je vybraný žánr Disco a interpretkou je Donna Summer.

Obrázek vybraného žánru Disco

Zkoumání ASP.NET kódu vygenerovaného v MVC

Otevřete soubor Controllers\StoreManagerController.cs a najděte metodu 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 přidá dva SelectList objekty do objektu ViewBag, jeden obsahuje informace o žánru a druhý k zahrnutí informací o interpretovi. Výše použité přetížení konstruktoru SelectList má tři argumenty:

public SelectList(

    IEnumerable items,

    string dataValueField,

    string dataTextField

)
  1. items: IEnumerable obsahující položky v seznamu. Ve výše uvedeném příkladu je seznam žánrů vrácených nástrojem db.Genres.
  2. dataValueField: Název vlastnosti v seznamu IEnumerable , která obsahuje hodnotu klíče. Ve výše uvedeném příkladu a GenreIdArtistId.
  3. dataTextField: Název vlastnosti v seznamu IEnumerable obsahující informace, které se mají zobrazit. V tabulce interpretů i žánrů se name použije pole .

Otevřete soubor Views\StoreManager\Create.cshtml a zkontrolujte 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í přebírá 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.

Výše uvedené přetížení Html.DropDownList přebírá název pole, které se má svázat s modelem. Používá také tento název k vyhledání objektu ViewBag obsahujícího SelectList objekt. Při použití tohoto přetížení je nutné pojmenovat objekt GenreIdViewBag SelectList . Druhý parametr (String.Empty) je text, který se zobrazí, 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")

Seznam výběrů by ve výchozím nastavení použil první prvek neboli Horninu v naší ukázce.

Obrázek výchozího prvního prvku

Prozkoumání HTTP POST Create 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 zaúčtovaných hodnot formuláře. Když odešlete nové album a stav modelu je platný a nedochází k žádným chybám databáze, nové album se přidá do databáze. Následující obrázek znázorňuje vytvoření nového alba.

Obrázek znázorňující vytvoření nového alba

Nástroj fiddler můžete použít k prozkoumání hodnot zaúčtovaných formulářů, které ASP.NET vazby modelu MVC používají k vytvoření objektu alba.

Obrázek nástroje Fiddler.

Refaktoring vytvoření viewbag selectList

Edit Metody i HTTP POST Create metoda mají stejný kód pro nastavení SelectList v ViewBag. V duchu funkce DRY tento kód refaktorujeme. 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é v ViewBag každé z Create metod a Edit nastaví hodnotu , voláním SetGenreArtistViewBag metody . Dokončený kód je zobrazený 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í SelectList do rozevíracího seznamu

Zobrazení pro vytváření a úpravy vytvořená generováním ASP.NET MVC používají 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 zobrazený níže.

@Html.DropDownList("GenreId", String.Empty)

Vzhledem k tomu, že ViewBag vlastnost objektu SelectList má název GenreId, bude pomocná rutina DropDownList používat GenreIdSelectList v oblasti ViewBag. V následujícím přetížení SelectListDropDownList je 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 tak, aby explicitně předal SelectList s využitím výše uvedeného přetížení. Udělejte to pro kategorii Žánr. Dokončený kód je zobrazený níže:

@Html.DropDownList("GenreId", ViewBag.GenreId as SelectList)

Spusťte aplikaci, klikněte na odkaz Správa, přejděte na album Jazz a vyberte odkaz Upravit.

Obrázek výběru jazzového alba pro úpravy

Místo toho, aby se jako aktuálně vybraný žánr zobrazoval Jazz, se zobrazí Rock. Pokud řetězcový argument (vlastnost pro vazbu) a objekt SelectList mají stejný název, vybraná hodnota se nepoužije. Pokud není zadaná žádná vybraná hodnota, prohlížeč ve výchozím nastavení použije první prvek v SelectList(což je v předchozím příkladu Rock ). Jedná se o 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 zobrazený 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 provedli dříve, se vyplašil. Místo změny ViewBag ve čtyřech metodách jsme změny izolovali na metodu SetGenreArtistViewBag .

Změňte volání DropDownList v zobrazení pro vytváření a úpravy tak, aby používalo nové názvy SelectList . Nová značka 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 pro úpravy výběrem alba s jiným žánrem než Rock.

Použití modelu zobrazení s pomocným nástrojem DropDownList

Ve složce ViewModels vytvořte novou třídu 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 pro žánry a umělce.

Sestavte projekt tak, AlbumSelectListViewModel aby 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 na AlbumSelectListViewModel, vyberte Vyřešit a pak použijte MvcMusicStore.ViewModels;.

Obrázek s výběrem řešení

Případně můžete přidat následující příkaz using:

using MvcMusicStore.ViewModels;

Klikněte pravým tlačítkem EditVM a vyberte Přidat zobrazení. Použijte možnosti uvedené níže.

Obrázek s dialogovým oknem Přidat zobrazení

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 formátu model.property(například model.Title ). Vlastnosti modelu v EditVm zobrazení jsou ve formátu model.Album.property(například model.Album.Title). Je to proto, že EditVM zobrazení je předáno kontejneru Albumpro , ne jako Album v Edit zobrazení.
  • Druhý parametr DropDownList pochází z modelu zobrazení, nikoli z ViewBag.
  • Pomocník BeginForm v EditVM zobrazení explicitně odešle zpět do Edit metody akce. Odesláním zpět do Edit akce nemusíme napsat HTTP POST EditVM akci a můžeme akci znovu použít HTTP POSTEdit .

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.

Obrázek s U R L změnou na Upravit V M

Jaký přístup byste měli použít?

Všechny tři uvedené přístupy jsou přijatelné. Mnoho vývojářů dává přednost explicitně předat SelectList nástroji DropDownList pomocí ViewBag. Tento přístup má další výhodu v tom, že poskytuje flexibilitu používání vhodnějšího názvu kolekce. Jediným upozorněním je, že objekt nemůžete pojmenovat ViewBag SelectList stejným názvem jako vlastnost modelu.

Někteří vývojáři dávají přednost přístupu ViewModel. Jiní považují podrobnější značky a vygenerované HTML přístupu ViewModel za nevýhodu.

V této části jsme se seznámili se třemi přístupy k použití rozevíracího seznamu s daty kategorií. V další části si ukážeme, jak přidat novou kategorii.