ASP.NET MVC가 DropDownList 도우미를 스캐폴드하는 방법 검사
작성자: Rick Anderson
솔루션 탐색기 Controllers 폴더를 마우스 오른쪽 단추로 클릭한 다음 컨트롤러 추가를 선택합니다. 컨트롤러 의 이름을 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 <select>
요소(HTML DropDownList 도우미가 만든)는 전체 값 목록(예: 장르 목록)을 표시하는 데 사용됩니다. 편집 폼의 경우 현재 값이 알려지면 선택 목록에 현재 값이 표시 될 수 있습니다. 이전에 선택한 값을 코미디로 설정했을 때 이 것을 보았습니다. 선택 목록은 범주 또는 외래 키 데이터를 표시하는 데 적합합니다. <select>
장르 외래 키의 요소는 가능한 장르 이름 목록을 표시하지만 형식을 저장하면 Genre 속성이 표시된 장르 이름이 아닌 Genre 외래 키 값으로 업데이트됩니다. 아래 이미지에서 선택한 장르는 디스코이고 아티스트는 도나 서머입니다.
ASP.NET MVC 스캐폴드 코드 검사
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
)
- items: 목록의 항목을 포함하는 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
위에 표시된 메서드에서 모델이 전달되지 않았기 때문에 뷰는 null Album
모델을 가져옵니다. 이 시점에서 우리는 그것에 대한 데이터가 없 Album
도록 새 앨범을 만들고 있습니다.
위에 표시된 Html.DropDownList 오버로드는 모델에 바인딩할 필드의 이름을 사용합니다. 또한 이 이름을 사용하여 SelectList 개체가 포함된 ViewBag 개체를 찾 습니다. 이 오버로드를 사용하여 ViewBag SelectList 개체GenreId
의 이름을 지정해야 합니다. 두 번째 매개 변수(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
이 오버로드는 게시된 양식 값에서 ASP.NET MVC 모델 바인딩 시스템에서 만든 개체를 사용합니다 album
. 새 앨범을 제출할 때 모델 상태가 유효하고 데이터베이스 오류가 없는 경우 새 앨범이 데이터베이스에 추가됩니다. 다음 이미지는 새 앨범의 생성을 보여줍니다.
fiddler 도구를 사용하여 ASP.NET MVC 모델 바인딩이 앨범 개체를 만드는 데 사용하는 게시된 양식 값을 검사할 수 있습니다.
.
ViewBag SelectList 만들기 리팩터링
Edit
메서드와 HTTP POST Create
메서드에는 모두 ViewBag에서 SelectList를 설정하는 동일한 코드가 있습니다. 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);
}
각 Create
및 Edit
메서드의 두 줄 설정을 ViewBag
메서드에 대한 호출 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);
}
새 앨범을 만들고 앨범을 편집하여 변경 내용이 작동하는지 확인합니다.
DropDownList에 SelectList 명시적으로 전달
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)
속성 SelectList
의 ViewBag
이름이 지정GenreId
되므로 DropDownList 도우미는 ViewBag에서GenreId
SelectList를 사용합니다. 다음 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)
애플리케이션을 실행하고 관리자 링크를 클릭한 다음 Jazz 앨범으로 이동하여 편집 링크를 선택합니다.
현재 선택한 장르로 재즈를 표시하는 대신, 록이 표시됩니다. 문자열 인수(바인딩할 속성)와 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);
}
장르 및 아티스트 이름은 각 범주의 ID 이상을 포함하므로 범주에 더 적합한 이름입니다. 우리가 이전에 한 리팩터링이 결실을 맺었습니다. 네 가지 메서드로 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 접근 방식을 선호합니다. 다른 사람들은 ViewModel 접근 방식의 더 자세한 태그 및 생성된 HTML을 단점으로 간주합니다.
이 섹션에서는 범주 데이터와 함께 DropDownList를 사용하는 세 가지 방법을 알아보았습니다. 다음 섹션에서는 새 범주를 추가하는 방법을 보여 드리겠습니다.