Общие сведения о формировании шаблона вспомогательного приложения DropDownList в ASP.NET MVC
В Обозреватель решений щелкните правой кнопкой мыши папку "Контроллеры", а затем выберите "Добавить контроллер". Назовите контроллер StoreManagerController. Задайте параметры диалогового окна "Добавить контроллер", как показано на рисунке ниже.
Измените представление StoreManager\Index.cshtml и удалите AlbumArtUrl
его. Удаление AlbumArtUrl
сделает презентацию более доступной для чтения. Ниже приведен готовый код.
@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>
Откройте файл Controllers\StoreManagerController.cs и найдите Index
метод. OrderBy
Добавьте предложение, чтобы альбомы были отсортированы по цене. Полный код показан ниже.
public ViewResult Index()
{
var albums = db.Albums.Include(a => a.Genre).Include(a => a.Artist)
.OrderBy(a => a.Price);
return View(albums.ToList());
}
Сортировка по цене упрощает тестирование изменений в базе данных. При тестировании методов редактирования и создания можно использовать низкую цену, чтобы сохраненные данные отображались сначала.
Откройте файл StoreManager\Edit.cshtml. Добавьте следующую строку сразу после тега условных обозначений.
@Html.HiddenFor(model => model.AlbumId)
В следующем коде показан контекст этого изменения:
@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
внести изменения в запись альбома.
Для запуска приложения нажмите сочетание клавиш CTRL+F5. Выберите ссылку "Администратор" , а затем щелкните ссылку "Создать" , чтобы создать новый альбом. Убедитесь, что сведения о альбоме сохранены. Измените альбом и убедитесь, что внесенные изменения сохраняются.
Схема альбома
Контроллер StoreManager
, созданный механизмом формирования шаблонов MVC, позволяет CRUD (Создать, чтение, обновление, удаление) доступ к альбомам в базе данных хранилища музыки. Схема для сведений о альбоме показана ниже:
Таблица Albums
не хранит жанр и описание альбома, он хранит внешний ключ к Genres
таблице. Таблица Genres
содержит имя и описание жанра. Аналогичным образом Albums
, таблица не содержит названия исполнителей альбома, но внешний ключ к Artists
таблице. Таблица Artists
содержит имя художника. При проверке данных в Albums
таблице можно увидеть, что каждая строка содержит внешний ключ Genres
к таблице и внешний ключ к Artists
таблице. На рисунке Albums
ниже показаны некоторые данные таблицы из таблицы.
Тег выбора HTML
Элемент HTML (созданный вспомогательным элементом HTML <select>
DropDownList ) используется для отображения полного списка значений (например, списка жанров). При изменении форм, когда известно текущее значение, список выбора может отображать текущее значение. Мы видели это ранее, когда мы установили выбранное значение комедии. Список выбора идеально подходит для отображения данных категории или внешнего ключа. Элемент <select>
внешнего ключа "Жанр" отображает список возможных имен жанров, но при сохранении формы свойство "Жанр" обновляется значением внешнего ключа "Жанр", а не отображаемым именем жанра. На изображении ниже выбран жанр Диско , и художник Донна Лето.
Изучение шаблона MVC ASP.NET
Откройте файл Controllers\StoreManagerController.cs и найдите HTTP GET Create
метод.
public ActionResult Create()
{
ViewBag.GenreId = new SelectList(db.Genres, "GenreId", "Name");
ViewBag.ArtistId = new SelectList(db.Artists, "ArtistId", "Name");
return View();
}
Этот Create
метод добавляет два объекта SelectList в ViewBag
один, чтобы содержать сведения о жанре, а один — для хранения сведений о художнике. Перегрузка конструктора SelectList , используемая выше, принимает три аргумента:
public SelectList(
IEnumerable items,
string dataValueField,
string dataTextField
)
- элементы: IEnumerable, содержащий элементы в списке. В приведенном выше примере список жанров, возвращаемых
db.Genres
. - dataValueField: имя свойства в списке IEnumerable , содержащего значение ключа. В приведенном выше
GenreId
примере иArtistId
. - dataTextField: имя свойства в списке IEnumerable , содержащее отображаемые сведения. В таблице художников и жанров
name
используется поле.
Откройте файл Views\StoreManager\Create.cshtml и проверьте вспомогательный Html.DropDownList
разметку для поля жанра.
@model MvcMusicStore.Models.Album
@* Markup removed for clarity.*@
@Html.DropDownList("GenreId", String.Empty)
В первой строке показано, что представление создания принимает Album
модель. В приведенном выше методе Create
не было передано никакой модели, поэтому представление получает пустую Album
модель. На этом этапе мы создадим новый альбом, поэтому у нас нет Album
данных для него.
Перегрузка Html.DropDownList , показанная выше, принимает имя поля для привязки к модели. Он также использует это имя для поиска объекта ViewBag , содержащего объект SelectList . Используя эту перегрузку, необходимо присвоить имя объекту GenreId
ViewBag SelectList. Второй параметр (String.Empty
) — это текст, отображаемый при отсутствии выбранного элемента. Это именно то, что мы хотим при создании нового альбома. Если вы удалили второй параметр и использовали следующий код:
@Html.DropDownList("GenreId")
Список выбора по умолчанию будет использовать первый элемент или Rock в нашем примере.
Изучение 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);
}
Эта перегрузка Create
метода принимает album
объект, созданный системой привязки модели MVC ASP.NET из опубликованных значений формы. При отправке нового альбома, если состояние модели допустимо и нет ошибок базы данных, новый альбом добавляется в базу данных. На следующем рисунке показано создание нового альбома.
Вы можете использовать средство fiddler для изучения опубликованных значений формы, которые ASP.NET привязка модели MVC использует для создания объекта альбома.
.
Рефакторинг создания viewBag SelectList
Edit
Методы и HTTP POST Create
методы имеют идентичный код для настройки SelectList в ViewBag. В духе DRY мы рефакторингом этого кода. Позже мы будем использовать этот рефакторинг кода.
Создайте новый метод для добавления жанра и художника SelectList в 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);
}
Замените две строки, заданные ViewBag
в каждом из Create
Edit
методов вызовом SetGenreArtistViewBag
метода. Ниже приведен готовый код.
//
// 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);
}
Создайте новый альбом и измените альбом, чтобы проверить работу изменений.
Явное передача selectList в dropDownList
Представления создания и изменения, созданные ASP.NET шаблонов MVC, используют следующую перегрузку 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"
)
Ниже DropDownList
показана разметка для представления создания.
@Html.DropDownList("GenreId", String.Empty)
ViewBag
Так как свойство для имени SelectList
GenreId
, помощник DropDownList будет использовать GenreId
SelectList в ViewBag. В приведенной ниже перегрузке DropDownList SelectList
явно передается.
public static MvcHtmlString DropDownList(
this HtmlHelper htmlHelper,
string name, // The name of the ViewModel property to bind.
IEnumerable selectList // The SelectList
)
Откройте файл Views\StoreManager\Edit.cshtml и измените вызов DropDownList для явного передачи в SelectList с помощью перегрузки выше. Сделайте это для категории жанра. Полный код показан ниже:
@Html.DropDownList("GenreId", ViewBag.GenreId as SelectList)
Запустите приложение и щелкните ссылку "Администратор" , а затем перейдите к джазовой альбому и выберите ссылку "Изменить ".
Вместо отображения джаза в качестве выбранного в настоящее время жанра, Рок отображается. Если строковый аргумент (свойство для привязки) и объект SelectList имеют то же имя, выбранное значение не используется. Если выбранное значение не указано, браузеры по умолчанию имеют первый элемент в SelectList (который является Rock в приведенном выше примере). Это известное ограничение вспомогательного средства DropDownList .
Откройте файл Controllers\StoreManagerController.cs и измените имена объектов SelectList на Genres
и Artists
. Полный код показан ниже:
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);
}
Имена жанров и художников — это лучшие имена для категорий, так как они содержат больше, чем только идентификатор каждой категории. Рефакторинг, который мы сделали раньше, окупалось. Вместо изменения ViewBag в четырех методах наши изменения были изолированы от SetGenreArtistViewBag
метода.
Измените вызов DropDownList в представлении создания и изменения, чтобы использовать новые имена SelectList. Ниже показана новая разметка для представления редактирования:
<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>
Для создания представления требуется пустая строка, чтобы предотвратить отображение первого элемента в 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>
Создайте новый альбом и измените альбом, чтобы проверить работу изменений. Проверьте код редактирования, выбрав альбом с жанром, кроме Rock.
Использование модели представления с вспомогательным элементом DropDownList
Создайте класс в папке ViewModels с именем AlbumSelectListViewModel
. Замените код в AlbumSelectListViewModel
классе следующим образом:
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);
}
}
}
Конструктор AlbumSelectListViewModel
принимает альбом, список художников и жанров и создает объект, содержащий альбом, и SelectList
для жанров и художников.
Создайте проект так, чтобы AlbumSelectListViewModel
он был доступен при создании представления на следующем шаге.
EditVM
Добавьте метод в объект StoreManagerController
. Ниже приведен готовый код.
//
// 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
"Разрешить", а затем с помощью MvcMusicStore.ViewModels;.
Кроме того, можно добавить следующую инструкцию using:
using MvcMusicStore.ViewModels;
Щелкните правой кнопкой мыши и выберите EditVM
пункт "Добавить представление". Используйте приведенные ниже параметры.
Выберите " Добавить", а затем замените содержимое файла Views\StoreManager\EditVM.cshtml следующим образом:
@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
Разметка очень похожа на исходную Edit
разметку со следующими исключениями.
- Свойства модели в
Edit
представлении имеют формуmodel.property
(например,model.Title
). Свойства модели вEditVm
представлении имеют формуmodel.Album.property
(например,model.Album.Title
). Это связано с тем, чтоEditVM
представление передается контейнером для представленияAlbum
, а неAlbum
как в представленииEdit
. - Второй параметр DropDownList поступает из модели представления, а не viewBag.
- Вспомогательный элемент BeginForm в представлении
EditVM
явно публикуется обратно вEdit
метод действия. Записав действие обратно вEdit
действие, нам не нужно писатьHTTP POST EditVM
действие и повторно использоватьHTTP POST
Edit
действие.
Запустите приложение и измените альбом. Измените используемый URL-адрес EditVM
. Измените поле и нажмите кнопку "Сохранить ", чтобы убедиться, что код работает.
Какой подход следует использовать?
Показаны все три подхода. Многие разработчики предпочитают явно передавать их SelectList
DropDownList
в использование ViewBag
. Этот подход позволяет повысить гибкость использования более подходящего имени для коллекции. Одно из предостережение заключается в том, что объект нельзя назвать ViewBag SelectList
таким же именем, как свойство модели.
Некоторые разработчики предпочитают подход ViewModel. Другие считают более подробной разметкой и созданным HTML-кодом подхода ViewModel к недостатку.
В этом разделе мы узнали три подхода к использованию DropDownList с данными категории. В следующем разделе мы покажем, как добавить новую категорию.