Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
por Rick Anderson
No Gerenciador de Soluções, clique com o botão direito do mouse na pasta Controladores e selecione Adicionar Controlador. Nomeie o controlador StoreManagerController. Defina as opções para a caixa de diálogo Adicionar controlador, conforme mostrado na imagem abaixo.

Edite a exibição StoreManager\Index.cshtml e remova AlbumArtUrlo . A remoção AlbumArtUrl tornará a apresentação mais legível. O código completo é mostrado abaixo.
@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>
Abra o arquivo Controllers\StoreManagerController.cs e localize o Index método. Adicione a OrderBy cláusula para que os álbuns sejam classificados por preço. O código completo é mostrado abaixo.
public ViewResult Index()
{
var albums = db.Albums.Include(a => a.Genre).Include(a => a.Artist)
.OrderBy(a => a.Price);
return View(albums.ToList());
}
A classificação por preço facilitará o teste de alterações no banco de dados. Ao testar os métodos de edição e criação, você pode usar um preço baixo para que os dados salvos apareçam primeiro.
Abra o arquivo StoreManager\Edit.cshtml . Adicione a seguinte linha logo após a tag legenda.
@Html.HiddenFor(model => model.AlbumId)
O código a seguir mostra o contexto dessa alteração:
@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. -->
}
O AlbumId é necessário para fazer alterações em um registro de álbum.
Pressione CTRL+F5 para executar o aplicativo. Selecione o link Admin e, em seguida, selecione o link Criar novo para criar um novo álbum. Verifique se as informações do álbum foram salvas. Edite um álbum e verifique se as alterações feitas são mantidas.
O esquema do álbum
O StoreManager controlador criado pelo mecanismo de scaffolding MVC permite acesso CRUD (Criar, Ler, Atualizar, Excluir) aos álbuns no banco de dados da loja de música. O esquema para informações do álbum é mostrado abaixo:

A Albums tabela não armazena o gênero e a descrição do álbum, ela armazena uma chave estrangeira para a Genres tabela. A Genres tabela contém o nome e a descrição do gênero. Da mesma forma, a Albums tabela não contém o nome dos artistas do álbum, mas uma chave estrangeira para a Artists tabela. A Artists tabela contém o nome do artista. Se você examinar os dados na Albums tabela, poderá ver que cada linha contém uma chave estrangeira para a Genres tabela e uma chave estrangeira para a Artists tabela. A imagem abaixo mostra alguns dados da Albums tabela.

A tag HTML Select
O elemento HTML <select> (criado pelo auxiliar HTML DropDownList ) é usado para exibir uma lista completa de valores (como a lista de gêneros). Para formulários de edição, quando o valor atual é conhecido, a lista de seleção pode exibir o valor atual. Vimos isso anteriormente quando definimos o valor selecionado como Comédia. A lista de seleção é ideal para exibir dados de categoria ou chave estrangeira. O <select> elemento da chave estrangeira Genre exibe a lista de possíveis nomes de gênero, mas quando você salva o formulário, a propriedade Genre é atualizada com o valor da chave estrangeira Genre, não com o nome do gênero exibido. Na imagem abaixo, o gênero selecionado é Disco e a artista é Donna Summer.

Examinando o código de scaffolded do MVC ASP.NET
Abra o arquivo Controllers\StoreManagerController.cs e localize o HTTP GET Create método.
public ActionResult Create()
{
ViewBag.GenreId = new SelectList(db.Genres, "GenreId", "Name");
ViewBag.ArtistId = new SelectList(db.Artists, "ArtistId", "Name");
return View();
}
O Create método adiciona dois objetos SelectList ao ViewBag, um para conter as informações de gênero e outro para conter as informações do artista. A sobrecarga do construtor SelectList usada acima usa três argumentos:
public SelectList(
IEnumerable items,
string dataValueField,
string dataTextField
)
- items: um IEnumerable que contém os itens na lista. No exemplo acima, a lista de gêneros retornada por
db.Genres. - dataValueField: o nome da propriedade na lista IEnumerable que contém o valor da chave. No exemplo acima,
GenreIdeArtistId. - dataTextField: o nome da propriedade na lista IEnumerable que contém as informações a serem exibidas. Tanto na tabela de artistas quanto na de gênero, o
namecampo é usado.
Abra o arquivo Views\StoreManager\Create.cshtml e examine a Html.DropDownList marcação auxiliar para o campo de gênero.
@model MvcMusicStore.Models.Album
@* Markup removed for clarity.*@
@Html.DropDownList("GenreId", String.Empty)
A primeira linha mostra que a visualização de criação usa um Album modelo. Create No método mostrado acima, nenhum modelo foi passado, portanto, a exibição obtém um modelo nuloAlbum. Neste ponto, estamos criando um novo álbum, então não temos dados Album para ele.
A sobrecarga Html.DropDownList mostrada acima usa o nome do campo a ser associado ao modelo. Ele também usa esse nome para procurar um objeto ViewBag que contém um objeto SelectList . Usando essa sobrecarga, você deve nomear o objeto GenreIdViewBag SelectList . O segundo parâmetro (String.Empty) é o texto a ser exibido quando nenhum item for selecionado. Isso é exatamente o que queremos ao criar um novo álbum. Se você removeu o segundo parâmetro e usou o seguinte código:
@Html.DropDownList("GenreId")
A lista de seleção seria padronizada para o primeiro elemento, ou Rock em nosso exemplo.

Examinando o HTTP POST Create método.
//
// 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);
}
Essa sobrecarga do Create método usa um album objeto, criado pelo sistema de associação de modelo MVC ASP.NET dos valores de formulário postados. Quando você envia um novo álbum, se o estado do modelo for válido e não houver erros de banco de dados, o novo álbum será adicionado ao banco de dados. A imagem a seguir mostra a criação de um novo álbum.

Você pode usar a ferramenta fiddler para examinar os valores de formulário postados que ASP.NET associação de modelo MVC usa para criar o objeto de álbum.
.
Refatoração da criação de ViewBag SelectList
Edit Os métodos e o HTTP POST Create método têm código idêntico para configurar o SelectList no ViewBag. No espírito do DRY, vamos refatorar esse código. Usaremos esse código refatorado posteriormente.
Crie um novo método para adicionar um gênero e um artista SelectList ao 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);
}
Substitua as duas linhas que definem o ViewBag em cada um dos Create métodos e Edit por uma chamada para o SetGenreArtistViewBag método. O código completo é mostrado abaixo.
//
// 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);
}
Crie um novo álbum e edite-o para verificar se as alterações funcionam.
Passando explicitamente o SelectList para o DropDownList
As exibições de criação e edição criadas pelo scaffolding MVC ASP.NET usam a seguinte sobrecarga 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"
)
A DropDownList marcação para a visualização de criação é mostrada abaixo.
@Html.DropDownList("GenreId", String.Empty)
Como a ViewBag propriedade do SelectList é nomeada GenreId, o auxiliar DropDownList usará oGenreId SelectList no ViewBag. Na sobrecarga DropDownList a seguir, o SelectList é explicitamente passado.
public static MvcHtmlString DropDownList(
this HtmlHelper htmlHelper,
string name, // The name of the ViewModel property to bind.
IEnumerable selectList // The SelectList
)
Abra o arquivo Views\StoreManager\Edit.cshtml e altere a chamada DropDownList para passar explicitamente o SelectList, usando a sobrecarga acima. Faça isso para a categoria Gênero. O código completo é mostrado abaixo:
@Html.DropDownList("GenreId", ViewBag.GenreId as SelectList)
Execute o aplicativo e clique no link Admin , navegue até um álbum do Jazz e selecione o link Editar .

Em vez de mostrar Jazz como o gênero selecionado no momento, Rock é exibido. Quando o argumento de cadeia de caracteres (a propriedade a ser associada) e o objeto SelectList têm o mesmo nome, o valor selecionado não é usado. Quando não há nenhum valor selecionado fornecido, os navegadores usam como padrão o primeiro elemento no SelectList (que é Rock no exemplo acima). Essa é uma limitação conhecida do auxiliar DropDownList .
Abra o arquivo Controllers\StoreManagerController.cs e altere os nomes dos objetos SelectList para Genres e Artists. O código completo é mostrado abaixo:
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);
}
Os nomes Gêneros e Artistas são nomes melhores para as categorias, pois contêm mais do que apenas o ID de cada categoria. A refatoração que fizemos anteriormente valeu a pena. Em vez de alterar o ViewBag em quatro métodos, nossas alterações foram isoladas no SetGenreArtistViewBag método.
Altere a chamada DropDownList nos modos de exibição de criação e edição para usar os novos nomes SelectList . A nova marcação para a visualização de edição é mostrada abaixo:
<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>
O modo de exibição Criar requer uma cadeia de caracteres vazia para impedir que o primeiro item na SelectList seja exibido.
<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>
Crie um novo álbum e edite-o para verificar se as alterações funcionam. Teste o código de edição selecionando um álbum com um gênero diferente de Rock.
Usando um modelo de exibição com o auxiliar DropDownList
Crie uma nova classe na pasta ViewModels chamada AlbumSelectListViewModel. Substitua o AlbumSelectListViewModel código na classe pelo seguinte:
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);
}
}
}
O AlbumSelectListViewModel construtor pega um álbum, uma lista de artistas e gêneros e cria um objeto contendo o álbum e um SelectList para gêneros e artistas.
Construa o projeto para que ele AlbumSelectListViewModel esteja disponível quando criarmos uma exibição na próxima etapa.
Adicione um EditVM método ao StoreManagerController. O código completo é mostrado abaixo.
//
// 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);
}
Clique com o botão direito do mouse AlbumSelectListViewModel, selecione Resolver e, em seguida , usando MvcMusicStore.ViewModels;.

Como alternativa, você pode adicionar a seguinte instrução using:
using MvcMusicStore.ViewModels;
Clique com o botão direito do mouse EditVM e selecione Adicionar exibição. Use as opções mostradas abaixo.

Selecione Adicionar e substitua o conteúdo do arquivo Views\StoreManager\EditVM.cshtml pelo seguinte:
@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>
A EditVM marcação é muito semelhante à marcação original Edit , com as seguintes exceções.
- As propriedades do
Editmodelo na vista são do formatomodel.property(por exemplo,model.Title). As propriedades doEditVmmodelo na vista são do formatomodel.Album.property(por exemplo,model.Album.Title). Isso ocorre porque aEditVMexibição recebe um contêiner para umAlbum, não umAlbumcomo naEditexibição. - O segundo parâmetro DropDownList vem do modelo de exibição, não do ViewBag.
- O auxiliar BeginForm no
EditVMmodo de exibição posta explicitamente de volta para oEditmétodo de ação. Ao postar de volta naEditação, não precisamos escrever umaHTTP POST EditVMação e podemos reutilizá-laHTTP POSTEdit.
Execute o aplicativo e edite um álbum. Altere o URL para usar EditVM. Altere um campo e clique no botão Salvar para verificar se o código está funcionando.

Qual abordagem você deve usar?
Todas as três abordagens mostradas são aceitáveis. Muitos desenvolvedores preferem passar explicitamente o SelectList para o DropDownList usando o ViewBag. Essa abordagem tem a vantagem adicional de oferecer a flexibilidade de usar um nome mais apropriado para a coleção. A única ressalva é que você não pode nomear o ViewBag SelectList objeto com o mesmo nome que a propriedade model.
Alguns desenvolvedores preferem a abordagem ViewModel. Outros consideram a marcação mais detalhada e o HTML gerado da abordagem ViewModel uma desvantagem.
Nesta seção, aprendemos três abordagens para usar o DropDownList com dados de categoria. Na próxima seção, mostraremos como adicionar uma nova categoria.