1

今天我决定试一试 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 %>
    <% } %>

<% } %>

所有反馈表示赞赏。

4

2 回答 2

2

至于for对嵌套转发器行为使用循环,我认为这是在 MVC 中执行此操作的最佳方法。但我建议您使用专用的 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 %>
    <% } %>
<% } %>

这种方法有几个优点:

  1. 它可以防止您的视图代码依赖于您的数据访问类。视图代码应该只负责决定如何将所需的视图模型呈现为 HTML。
  2. 它将与显示无关的逻辑排除在您的视图代码之外。如果您稍后决定分页您的问题,并且现在显示问题 11-20 而不是 1-whatever,您可以使用完全相同的视图,因为控制器负责确定要显示的问题编号。
  3. 它可以更轻松地避免在循环中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};
}
于 2010-12-03T21:37:32.877 回答
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

于 2010-12-03T21:01:15.593 回答