今天我决定给MVC一个机会,虽然我非常喜欢这个想法,但我发现从ASP.NET过渡并掌握一些基本概念相当困难,比如使用foreach而不是嵌套的中继器。
我花了好几个小时来提出这个解决方案,但这似乎并不合适。有人可以解释这个代码有什么问题,以及正确的方法是什么。这是我的解决方案:
基本上,这是一项由几个问题组成的调查,每个问题都有几个答案。我在db中有表,它们表示为强类型实体。控制器如下所示:
public ActionResult Details(int id)
{
return View(new Models.Entities().Questions.Where(r => r.PROMId == id));
}
和相应的观点如下:
<% foreach (var question in Model) { %>
<h3>Question <%: Array.IndexOf(Model.ToArray(), question) + 1 %></h3>
<p><%: question.QuestionPart1 %></p>
<p><%: question.QuestionPart2 %></p>
<% var answers = new Surveys_MVC.Models.Entities().Answers.Where(r => r.QuestionId == question.QuestionId); %>
<% foreach (var answer in answers) { %>
<input type="radio" /><%: answer.Text %>
<% } %>
<% } %>
所有反馈都表示赞赏。
答案 0 :(得分:2)
对于嵌套转发器行为使用for
循环,我认为这是在MVC中执行此操作的最佳方法。但我建议你使用专用的ViewModels。
视图模型:
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 %>
<% } %>
<% } %>
这种方法有一些优点:
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};
}
答案 1 :(得分:0)
我不知道它是否更好,但您可以创建一个帮助程序来为您执行此操作:
public static void Repeater<T>(this HtmlHelper html, IEnumerable<T> items, string cssClass, string altCssClass, string cssLast, Action<T, string> render)
{
if (items == null)
return;
var i = 0;
foreach (var item in items)
{
i++;
if (i == items.Count())
render(item, cssLast);
else
render(item, (i % 2 == 0) ? cssClass : altCssClass);
}
}
然后你可以这样称呼它:
<%Html.Repeater(Model, "css", "altCss", "lastCss", (question, css) => { %>
<h3>Question <%: Array.IndexOf(Model.ToArray(), question) + 1 %></h3>
<p><%: question.QuestionPart1 %></p>
<p><%: question.QuestionPart2 %></p>
<% var answers = new Surveys_MVC.Models.Entities().Answers.Where(r => r.QuestionId == question.QuestionId); %>
<% foreach (var answer in answers) { %>
<input type="radio" /><%: answer.Text %>
<% } %>
<% }); %>
这有很多权力,上面只是一个例子。您可以在此处阅读更多内容http://haacked.com/archive/2008/05/03/code-based-repeater-for-asp.net-mvc.aspx