Что касается использования циклов for
для поведения вложенных повторителей, я думаю, что это лучший способ сделать это в MVC. Но я бы посоветовал вам использовать специальные ViewModels.
ViewModel:
public class RadioQuestionListViewModel
{
public IEnumerable<RadioQuestionViewModel> Questions {get;set;}
}
public class RadioQuestionViewModel
{
public int QuestionNumber {get;set;}
public string InputName {get;set;}
public string QuestionPart1 {get;set;}
public string QuestionPart2 {get;set;}
public IEnumerable<RadioAnswerViewModel> PossibleAnswers {get;set;}
}
public class RadioAnswerViewModel
{
public int AnswerId {get;set;}
public string Text {get;set;}
}
Контроллер:
public ActionResult Details(int id)
{
var model = GetRadioQuestionListModelById(id);
return View(model);
}
Вид:
<% foreach (var question in Model) { %>
<h3>Question <%: question.QuestionNumber %></h3>
<p><%: question.QuestionPart1 %></p>
<p><%: question.QuestionPart2 %></p>
<% foreach (var answer in question.PossibleAnswers) { %>
<%: Html.RadioButton(question.InputName, answer.AnswerId) %>
<%: answer.Text %>
<% } %>
<% } %>
Этот подход имеет несколько преимуществ:
- Он не позволяет вашему коду просмотра зависеть от ваших классов доступа к данным. Код представления должен отвечать только за принятие решения о том, как требуемая модель представления будет отображаться в HTML.
- Он не допускает никакой логики, связанной с отображением, в вашем коде представления. Если вы позже решите разместить свои вопросы на странице и теперь будете показывать вопросы 11-20 вместо 1 - что угодно, вы можете использовать точно такое же представление, потому что контроллер позаботился о поиске номеров вопросов для отображения.
- Упрощается избегать выполнения
Array.IndexOf(Model.ToArray(), question)
и обращения к базе данных внутри цикла for
, что может стать довольно дорогостоящим, если у вас есть несколько вопросов на странице.
И, конечно, ваши радиокнопки должны иметь имя и значение ввода, связанные с ними, иначе вы не сможете получить эту информацию при отправке формы. Заставив контроллер решить, как генерируется входное имя, вы сделаете более очевидным, как метод Details
соответствует вашему методу SaveAnswers
.
Вот возможная реализация GetRadioQuestionListModelById
:
public RadioQuestionListViewModel GetRadioQuestionListModelById(int id)
{
// Make sure my context gets disposed as soon as I'm done with it.
using(var context = new Models.Entities())
{
// Pull all the questions and answers out in a single round-trip
var questions = context.Questions
.Where(r => r.PROMId == id)
.Select(r => new RadioQuestionViewModel
{
QuestionPart1 = r.q.QuestionPart1,
QuestionPart2 = r.q.QuestionPart2,
PossibleAnswers = r.a.Select(
a => new RadioAnswerViewModel
{
AnswerId = a.AnswerId,
Text = a.Text
})
})
.ToList();
}
// Populate question number and name
for(int i = 0; i < questions.Count; i++)
{
var q = questions[i];
q.QuestionNumber = i;
q.InputName = "Question_" + i;
}
return new RadioQuestionListViewModel{Questions = questions};
}