ASP.net MVC DropDownList значение, используемое для создания нового объекта

2

Кажется, это довольно простая проблема, с которой я столкнулся около часа, и я не понимаю, что я делаю неправильно.

У меня есть ViewModel:

public class SongFormViewModel
    {
        public Song Song { get; set; }
        public SelectList AlbumList { get; set; }

        public SongFormViewModel(Song song, IQueryable<Album> albumList)
        {
            Song = song;
            AlbumList = new SelectList(albumList, "AlbumId", "Title", song.AlbumId);  
        }
    }

У меня есть представление Create:

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<NightSpot.Models.SongFormViewModel>" %>

<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
    Create
</asp:Content>

<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">

    <h2>Create</h2>

    <%= Html.ValidationSummary("Create was unsuccessful. Please correct the errors and try again.") %>

    <% using (Html.BeginForm()) {%>

        <fieldset>
            <legend>Fields</legend>
            <p>
                <label for="AlbumId">AlbumId:</label>
                <%= Html.DropDownList("AlbumId", Model.AlbumList) %>
                <%= Html.ValidationMessage("AlbumId", "*") %>
            </p>
            <p>
                <label for="Title">Title:</label>
                <%= Html.TextBox("Title") %>
                <%= Html.ValidationMessage("Title", "*") %>
            </p>
            <p>
                <label for="TrackNumber">TrackNumber:</label>
                <%= Html.TextBox("TrackNumber") %>
                <%= Html.ValidationMessage("TrackNumber", "*") %>
            </p>
            <p>
                <input type="submit" value="Create" />
            </p>
        </fieldset>

    <% } %>

    <div>
        <%=Html.ActionLink("Back to List", "Index") %>
    </div>

</asp:Content>

И у меня есть метод SongsController Create:

        //
        // POST: /Songs/Create

        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult Create(Song song)
        {
            if (ModelState.IsValid)
            {
                try
                {
                    repository.Add(song);
                    repository.Save();

                    return RedirectToAction("Details", new { id = song.SongId });
                }
                catch
                {
                    ModelState.AddRuleViolations(song.GetRuleViolations());
                }
            }

            return View(new SongFormViewModel(song, repository.FindAllAlbums()));
        }

Когда я перехожу к /Songs/Create URL, я вижу ожидаемый интерфейс. Мой раскрывающийся список содержит список всех действующих альбомов в моей базе данных (из таблицы "Альбомы" ), и я подтвердил, что каждое значение AlbumId является значением, и каждый заголовок является текстом. Отлично.

Итак, теперь, когда я отправляюсь заполнять свою форму и нажимаю "Сохранить", я получаю сообщение о том, что мне нужно выбрать альбом. Когда я перехожу к отладчику в Visual Web Developer, я вижу, что номер заголовка и трека заполняется правильно, но мой объект Album равен NULL, а AlbumId - 0. Все идеи?

UPDATE

Отвечая Мэтту, я обновил свой SongsController, чтобы использовать SongFormViewModel вместо Песни. Здесь новый контроллер:

        //
        // POST: /Songs/Create

        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult Create(SongFormViewModel song)
        {
            Song newSong = song.Song;
            newSong.AlbumId = (int) song.AlbumList.SelectedValue;

            if (ModelState.IsValid)
            {
                try
                {
                    repository.Add(newSong);
                    repository.Save();

                    return RedirectToAction("Details", new { id = song.Song.SongId });
                }
                catch
                {
                    ModelState.AddRuleViolations(song.Song.GetRuleViolations());
                }
            }

            return View(new SongFormViewModel(newSong, repository.FindAllAlbums()));
        }

Я активировал свой /Songs/Create URL и получил сообщение о том, что SongFormViewModel требует конструктора без параметров.

Итак, я сделал один.

Когда я повторно запускал /Songs/Create URL, я получил исключение "Object reference not set to a instance of object" в этой строке в моем SongsController:

Line 93:             newSong.AlbumId = (int) song.AlbumList.SelectedValue;

Идеи?

UPDATE

ОК, поэтому я обновил свой взгляд на предложение Мэтта о префиксах полей "Песня":

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<NightSpot.Models.SongFormViewModel>" %>

<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
    Create
</asp:Content>

<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">

    <h2>Create</h2>

    <%= Html.ValidationSummary("Create was unsuccessful. Please correct the errors and try again.") %>

    <% using (Html.BeginForm()) {%>

        <fieldset>
            <legend>Fields</legend>
            <p>
                <label for="Song.AlbumId">AlbumId:</label>
                <%= Html.DropDownList("Song.AlbumId", Model.AlbumList) %>
                <%= Html.ValidationMessage("Song.AlbumId", "*") %>
            </p>
            <p>
                <label for="Song.Title">Title:</label>
                <%= Html.TextBox("Song.Title") %>
                <%= Html.ValidationMessage("Song.Title", "*") %>
            </p>
            <p>
                <label for="Song.TrackNumber">TrackNumber:</label>
                <%= Html.TextBox("Song.TrackNumber") %>
                <%= Html.ValidationMessage("Song.TrackNumber", "*") %>
            </p>
            <p>
                <input type="submit" value="Create" />
            </p>
        </fieldset>

    <% } %>

    <div>
        <%=Html.ActionLink("Back to List", "Index") %>
    </div>

</asp:Content>

Поведение, к сожалению, такое же. Null SelectedValue и пустой объект Song.

  • 0
    Так что я предполагаю, что song.AlbumList равен нулю, когда он входит в ваш метод действия? Является ли song.Song null или все прошло нормально?
  • 0
    О, теперь это интересно ... SongFormViewModel.AlbumList.SelectedValue принимает значение NULL, а SongFormViewModel.Song выглядит в состоянии после вызова нового конструктора Song (). Даже текстовые поля не заполнены на песню. Песня, в отличие от ранее.
Показать ещё 5 комментариев
Теги:
asp.net-mvc

3 ответа

1
Лучший ответ

Вы пытаетесь использовать MVC как классический ASP.NET

MVC возвращает исходные значения HTTP-сообщения, а помощники по умолчанию с MVC пытаются преобразовать их в основные модели

Вы можете получить значение выбранного списка, например. AlbumId, но не сложные типы, такие как AlbumList.SelectedValue

Попробуйте что-то вроде этого

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(int albumId, ...)

SongFormViewModel не помогает вам здесь. Он не отражает то, что вы действительно хотите. Он должен иметь что-то вроде выбранного в настоящее время альбома в качестве поля

  • 0
    Спасибо! Это именно то, что сделал трюк!
1

Я только сейчас изучаю этот материал сам, но из того, что я понимаю, передавая song.AlbumId в конструктор SelectList, только устанавливает начальное выбранное значение списка. Он не привязывает список к свойству Album объекта песни.

В вашем методе Create вам придется вручную назначить альбом, представленный выбранным элементом, в списке SongFormViewModel.Albums. Вы можете использовать свойство SelectedValue для извлечения идентификатора альбома, выбранного пользователем в этом случае. Вам нужно будет передать его в int (или Guid - независимо от типа AlbumId).

Конечно, это означает, что вам нужен доступ к классу ViewModel из вашего метода Create, а не только к созданной песне. Я вполне уверен, что вы можете просто изменить тип параметра из песни в SongFormViewModel, и пусть связующее по умолчанию позаботится об этом для вас.

Дайте мне знать, как вы поживаете - я очень хочу узнать больше об этом, поэтому я хотел бы увидеть окончательное решение!

  • 0
    Спасибо, Мэтт! Я попробую!
  • 0
    Смотрите мои обновления ... получить исключение ...
0

ИЗМЕНИТЬ

Если вы хотите сохранить свою существующую модель. Измените свой SongFormViewModel на этот

public class SongFormViewModel
{
        public Song Song { get; set; }
        public SelectList AlbumList { get; set; }
}

а затем измените

return View(new SongFormViewModel(song, repository.FindAllAlbums()));

к

var songFormViewModel = new SongFormViewModel();
songFormViewModel.AlbumList = repository.FindAllAlbums();
songFormViewModel.Song = song;
return View(songFormViewModel);

-

Ваше представление должно быть строго типизированным типом Song not SongFormViewModel. Поэтому измените

Inherits="System.Web.Mvc.ViewPage<NightSpot.Models.SongFormViewModel>"

to

Inherits="System.Web.Mvc.ViewPage<NightSpot.Models.Song>"

Теперь избавьтесь от изменений полей префиксов. Это должно работать.

  • 0
    Тогда как мне получить доступ к значениям для моего выпадающего списка?
  • 0
    Вам нужно будет сохранить его в ViewData в вашем запросе Get. ViewData ["albumList"] = новый список <SelectListItem> {// Ваши записи здесь}.
Показать ещё 4 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню