ASP.net MVC DropDownList значение, используемое для создания нового объекта - PullRequest
2 голосов
/ 15 января 2010

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

У меня есть 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:

        //
        // 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, я вижуожидаемый интерфейс.Мой раскрывающийся список содержит список всех допустимых альбомов в моей базе данных (из таблицы «Альбомы»), и я проверил, что каждый идентификатор альбома является значением, а каждый заголовок - текстом.Отлично.

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

ОБНОВЛЕНИЕ

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

        //
        // 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, в моей строке SongsController появилось исключение «Ссылка на объект не установлен на экземпляр объекта»:

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

Идеи?

ОБНОВЛЕНИЕ

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

<%@ 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>

Поведениеэто, к сожалению, то же самое.Нулевое значение SelectedValue и пустой объект Song.

Ответы [ 3 ]

1 голос
/ 18 января 2010

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

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

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

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

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

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

1 голос
/ 15 января 2010

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

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

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

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

0 голосов
/ 15 января 2010

EDIT

Если вы хотите сохранить существующую модель. Измените свою 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, а не SongFormViewModel. Так что поменяй

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

до

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...