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. これにより、非表示関連のロジックがビュー コードから除外されます。後で質問をページングすることを決定し、1-whatever の代わりに質問 11-20 を表示している場合、まったく同じビューを使用できます。これは、コントローラーが表示する質問番号を計算することを処理するためです。
  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 に答える