@rgamretsky
SharePoint Develorep(а хочется в ASP.NET MVC dev)

Как передать определенный параметр элемента в списке?

Ситуация следующая. Есть Model1 в которой содержится list другого объекта(Model2) у которого есть свойство Text. Подскажите как формой передать в контроллер Model1 , а так же элемент списка Model2 который должен автоматически заполнится, а свойство Text взять значение с элемента формы.
Model1
public class PollModel
    {

        public string Id { get; set; }
        public string Question { get; set; }
        public IEnumerable<Answer> Answer { get; set; }
        public int Answered { get; set; }
        public string UserIdCreated { get; set; }
    }

Model2
public class Answer
    {
        [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public string Id { get; set; }
        public string QuestionId { get; set; }
        public string Text { get; set; }
        public int Chosen { get; set; }

    }

Контроллер
public ActionResult Create([Bind(Include = "Id,Question,Answer,Answered,UserIdCreated")] PollModel poll)
        {
            return View(poll);
        }

А так же часть представления с которого должно заполнятся свойство Text
<div class="form-group">
            @Html.LabelFor(model => model.Answer, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Answer.Single().Text, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.Answer.Single().Text, "", new { @class = "text-danger" })
            </div>
        </div>

Подскажите как полностью правильно заполнить IEnumerable Answer и передать в контроллер.
  • Вопрос задан
  • 3665 просмотров
Решения вопроса 1
Valeriy1991
@Valeriy1991
Разработчик .NET C# (ASP.NET MVC) в Alfa-B, Moscow
Добрый день!

1. Я, возможно, что-то немного не понял, но использовать тип string для поля Id - плохая практика. Используйте int вместо string.
2. Называйте переменные правильно: если у Вас список ответов, то лучше вместо "Answer" назовите Answers" или "AnswerList" - старайтесь писать такой код, чтобы с ним после Вас мог легко работать другой программист.
3. (на всякий случай) Для сообщений валидации можно использовать атрибуты (Required, MaxLength, ...) - я заметил, что в ValidationMessageFor Вы используете "" для текста сообщения валидации.
4. В классе Answer у Вас есть свойство Chosen - если я правильно понимаю, это "Выбран", т.е. это логическая переменная, которая может быть либо "Да", либо "Нет". Зачем используете тип int, ведь есть тип bool?
4. Не знаю, как у Вас, но не заполнив коллекцию Answer(s) в модели PollModel на сервере, Вы не сможете обращаться к ней через Single(), потому что в методе действия Create, который Вы привели, модель не заполняется, соответственно, коллекция Answer(s) равна null, в результате - ошибка, т.к. у null-объекта нельзя обращаться к свойствам. Поэтому Вам нужно как минимум сформировать модель на сервере, например, так:
[HttpGet]
public ActionResult Create()
{
     List<Answer> answers = new List<Answer>();
     answers.Add(new Answer() { Id = 1, QuestionId = 1, Text = "Вопрос №1", Chosen = false });
     PollModel viewModel = new PollModel()
     {
          Id = "1", 
          UserIdCreated = "user1",
          Answers = answers
     };
     return View(viewModel);
}

5. Т.к. у Вас коллекция Answer(s), то для правильной привязки нужно правильно сформировать View, потому что привязка к коллекциям в ASP.NET MVC осуществляется особым образом - если посмотрите на html-код, то увидите, что тег input, в который нужно ввести текст, имеет атрибут name="Answers[0].Text и атрибут id="Answers_0__Text". Так работает связыватель модели (Model Binder) в ASP.NET MVC по-умолчанию .

Рабочий пример - основан на шаблоне ASP.NET MVC 4 Internet Application в VS 2012:
HomeController.cs:
[HttpGet]
        public ActionResult Create()
        {
            List<Answer> answers = new List<Answer>();
            answers.Add(new Answer() { Id = 1, QuestionId = 1, Text = "Вопрос №1", Chosen = false });
            PollModel viewModel = new PollModel()
            {
                Id = "1", 
                UserIdCreated = "user1",
                Answers = answers
            };
            return View(viewModel);
        }

        [HttpPost]
        public ActionResult Create(PollModel viewModel)
        {
            TempData["Message"] = String.Format("Текст Вашего вопроса - {0}", viewModel.Answers.First().Text);
            return View(viewModel);
        }

Create.cshmtl:
@using TosterQuestion101113_MVC.Models;
@model PollModel

@{
    ViewBag.Title = "Create";
    Layout = "~/Views/Shared/_Layout.cshtml";
}

<h2>Create</h2>
<div class="form-group">
    @using (Html.BeginForm("Create", "Home", FormMethod.Post, null))
    {
        if (TempData["Message"] != null)
        {
            <div class="message">
                @TempData["Message"]
            </div>
        }
        
        @Html.LabelFor(e => e.Answers, new { @class = "control-label col-md-2" })
        for (int i = 0; i < Model.Answers.Count(); i++)
        {
            <div class="col-md-10">
            @Html.EditorFor(e => e.Answers[i].Text, new { htmlAttributes = new { @class = "form-control" } })
            @Html.ValidationMessageFor(e => e.Answers.Single().Text, "", new { @class = "text-danger" })
        </div>
        }
        
        <div>
            <input type="submit" value="ОК!" />
        </div>
    }
</div>


Замечания:
1. Свойство IEnumerable<Answer> Answer изменено на IList<Answer> Answers - потому, что Ilist предоставляет доступ к методу Count() для реализации перечисления в цикле
2. Answer.Single().Text изменено на Answers[i].Text
3. И вообще - у меня сложилось впечатление, что Вы начали недавно изучать ASP.NET MVC и в том числе не так давно программируете. Поэтому я вынужден настаивать: читайте от корки до корки книгу "ASP.NET MVC3 (либо 4) Framework с примерами на C# для профессионалов" - там всё просто отлично объяснен ASP.NET MVC.

Надеюсь, я Вам немного помог.
Успехов!
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы