2015-01-20 91 views
17

我開始了我的第一個ASP.NET MVC項目,所以我有一個簡單的問題。 我有以下代碼:ASP.NET MVC 5組單選按鈕

foreach(var question in Model.GeneralQuestions) 
{ 
    <div class = "well"> 
     <h3> 
      <strong>@question.QuestionString</strong> 
     </h3> 
     @foreach (var answer in question.PossibleAnswers) 
     { 
      @Html.RadioButtonFor(model => question.QuestionString, answer.Answer) 
      @Html.Label(answer.Answer) 
      <br /> 
     } 
    </div> 
} 

在Model.GeneralQuestions所有問題都是獨一無二的,所以單選按鈕應該由name屬性被分成組(每題一組單選按鈕)。但是這個代碼只產生一個組,所以當我第一個回答第二個問題時就會取消選擇。 我需要改變什麼?

編輯
我的模型看起來像:

public class StudentViewModel 
{ 
    public Student Student { get; set; } 
    public List<Question> GeneralQuestions { get; set; } 
    public List<SubjectQuestions> SubjectQuestions { get; set; } 
} 
public class Student 
{ 
    public int StudentID { get; set; } 
    public string Index { get; set; } 
    public string Name { get; set; } 
    public string Surname { get; set; } 

    public virtual ICollection<Subject> Subjects { get; set; } 
} 
public class Question 
{ 
    public int QuestionID { get; set; } 
    public string QuestionString { get; set; } 
    public bool IsAssociatedWithSubject { get; set; } 

    public virtual ICollection<PossibleAnswer> PossibleAnswers { get; set; } 
    public virtual ICollection<Results> Results { get; set; } 
} 
public class SubjectQuestions 
{ 
    public Subject Subject { get; set; } 
    public List<Question> Questions { get; set; } 
} 
public class Results 
{ 
    public int ResultsID { get; set; } 
    public int QuestionID { get; set; } 
    public int? SubjectID { get; set; } 
    public int PossibleAnswerID { get; set; } 

    public virtual Question Question { get; set; } 
    public virtual PossibleAnswer PossibleAnswer { get; set; } 
    public virtual Subject Subject { get; set; } 
} 

在StudentViewModel的一個實例我救一個學生,所有的問題,他應該回答(一般和相關學科他是學)和通它來查看。鑑於我將所有問題都以單一形式提出,並且都是無線電廣播。所以,任何人都可以幫助我分組單選按鈕並正確回覆此表單嗎?

+1

只是一個快速反應,但你見過這篇文章嗎? http://stackoverflow.com/a/22178728/1765853 – macoms01 2015-01-20 21:22:27

+0

只要'QuestionString'是唯一的,這應該是爲每個問題創建一個組,雖然綁定到'QuestionString'似乎是固定的 - 你不應該綁定到類似的東西'SelectedAnswer'?你可以顯示一些這是生成的HTML – 2015-01-20 21:27:39

+0

你的外循環也應該是一個'for'循環,這樣你的控件屬性可以通過索引器命名。 – 2015-01-20 21:30:50

回答

23

您的代碼有許多問題,包括生成重複的id的(無效的html),生成重複的name屬性(這就是爲什麼您只創建一個組,但更重要的是,這會阻止您綁定到當你回發)時,你實際上並沒有綁定到有效的屬性。

您需要創建視圖模型來表示要在for循環(或使用EditorTemplate)中顯示和編輯並生成單選按鈕,以便使用索引器正確命名它們。

查看模型

@model YourAssembly.StudentVM 
@using(Html.BeginForm()) 
{ 
    @Html.HiddenFor(m => m.ID) 
    @Html.DisplayFor(m => m.Name) 
    for(int i = 0; i < Model.Subjects.Count; i++) 
    { 
    @Html.HiddenFor(m => m.Subjects[i].ID) 
    @Html.DisplayFor(m => m.Subjects[i].Name) // will display "General" if no name 
    for (int j = 0; j < Model.Subjects[i].Questions.Count; j++) 
    { 
     @Html.HiddenFor(m => m.Subjects[i].Questions[j].ID) 
     @Html.DisplayFor(m => m.Subjects[i].Questions[j].Text) 
     foreach(var answer in Model.Subjects[i].Questions[j].PossibleAnswers) 
     { 
     <div> 
      @Html.RadioButtonFor(m => m.Subjects[i].Questions[j].SelectedAnswer, answer.ID, new { id = answer.ID}) 
      <label for="@answer.ID">@answer.Text</label> 
     </div> 
     } 
     @Html.ValidationMessageFor(m => m.Subjects[i].Questions[j].SelectedAnswer) 
    } 
    } 
    <input type="submit" value="save" /> 
} 

控制器

public ActionResult Edit(int ID) 
{ 
    StudentVM model = new StudentVM(); 
    // populate your view model with values from the database 
    return View(model); 
} 

[HttpPost] 
public ActionResult Edit(StudentVM model) 
{ 
    // save and redirect 
} 

注意我有點困惑,通過你的模型所隱含的數據庫結構(例如你爲什麼需要

public class QuestionVM 
{ 
    public int ID { get; set; } // for binding 
    public string Text { get; set; } 
    [Required] 
    public int? SelectedAnswer { get; set; } // for binding 
    public IEnumerable<AnswerVM> PossibleAnswers { get; set; } 
} 

public class SubjectVM 
{ 
    public int? ID { get; set; } 
    [DisplayFormat(NullDisplayText = "General")] 
    public string Name { get; set; } 
    public List<QuestionVM> Questions { get; set; } 
} 

public class AnswerVM 
{ 
    public int ID { get; set; } 
    public string Text { get; set; } 
} 

public class StudentVM 
{ 
    public int ID { get; set; } 
    public string Name { get; set; } 
    // plus any other properties of student that you want to display in the view 
    public List<SubjectVM> Subjects { get; set; } 
} 

查看QuestionSubjectQuestion的單獨型號爲null值爲SubjectID將其標識爲「常規」問題)。我建議你首先在GET方法中對某些值進行硬編碼,以查看它是如何工作並回發的。

StudentVM model = new StudentVM(); 
model.ID = 1; 
model.Name = "bambiinela"; 
model.Subjects = new List<SubjectVM>() 
{ 
    new SubjectVM() 
    { 
    Questions = new List<QuestionVM>() 
    { 
     new QuestionVM() 
     { 
     ID = 1, 
     Text = "Question 1", 
     SelectedAnswer = ?, // set this if you want to preselect an option 
     PossibleAnswers = new List<AnswerVM>() 
     { 
      new AnswerVM() 
      { 
      ID = 1, 
      Text = "Answer A" 
      }, 
      new AnswerVM() 
      { 
      ID = 1, 
      Text = "Answer B" 
      } 
     } 
     }, 
     new QuestionVM() 
     { 
     ID = 2, 
     Text = "Question 2", 
     PossibleAnswers = new List<AnswerVM>() 
     { 
      // similar to above 
     } 
     } 
    } 
    }, 
    new SubjectVM() 
    { 
    ID = 1, 
    Name = "Math", 
    Questions = new List<QuestionVM>() 
    { 
     // similar to above 
    } 
    } 
}; 

當您發佈時,模型會填入每個主題中每個問題的選定答案的ID。請注意,某些屬性使用DisplayFor()。這些將不會回發,因此如果您返回視圖,則需要重新填充這些屬性(例如ModelState無效)。或者,您可以爲這些屬性生成只讀文本框或添加隱藏輸入。我也建議你檢查所生成的HTML,尤其是name屬性,這將是這個樣子

<input type="radio" name="Subjects[0].Questions[0].SelectedAnswer" ... 

給你的藏品是如何綁定到模型上回發

+0

謝謝!所有的建議都很有幫助,代碼是正確的。現在我已經分離了MVC的模型,並將其保存在數據庫中,因爲我在數據庫中的實體應該看起來與MVC模型有點不同。 – bambi 2015-01-21 15:02:22

+0

是否有任何方式在StudentVM對象中發佈回問題文本,主題名稱等?我所得到的是post方法中回答問題的ID('[HttpPost] public ActionResult Student(StudentVM model) {}'),其他字段似乎是空的。 – bambi 2015-01-22 00:28:35

+0

正如我所指出的那樣,除了'@ Html.DisplayFor()'之外,您還可以爲這些屬性創建隱藏的輸入。 '@ H​​tml.HiddenFor(m => m.Name)''或者你可以用'@ Html.TextBoxFor(m => m.Name,new {@readonly =「readonly」,@ class =「readonly 「)'然後用css來設置它。然而,創建大量不必要的隱藏輸入可能會降低性能(將其發送給客戶端,然後再返回),並向您提供重複發佈攻擊的機會。通常情況下,再次從數據庫中獲取數據會更好,但只有您可以評估最佳選擇。 – 2015-01-22 00:51:50

2

訣竅的理解是使用一個表達式(Html.RadioButtonFor的第一個參數),其中包含一個值,每個單選按鈕組都會改變一個值。就你而言,它將成爲問題列表中的一個索引。

下面是一些示例代碼:

@for (int i = 0; i < Model.GeneralQuestions.Count; i++) 
{ 
    var question = Model.GeneralQuestions[i]; 
    @Html.Label(question.QuestionString) 
    <br /> 
    foreach (var answer in question.PossibleAnswers) 
    { 
     @Html.RadioButtonFor(model => 
      Model.GeneralQuestions[i].SelectedAnswerId, answer.Id) 
     @Html.Label(answer.Answer) 
     <br /> 
    } 
} 

這將產生以下HTML:

<label for="Q1">Q1</label> 
<br /> 
<input id="GeneralQuestions_0__SelectedAnswerId" 
    name="GeneralQuestions[0].SelectedAnswerId" type="radio" value="1" /> 
<label for="A01">A01</label> 
<br /> 
<input id="GeneralQuestions_0__SelectedAnswerId" 
    name="GeneralQuestions[0].SelectedAnswerId" type="radio" value="2" /> 
<label for="A02">A02</label> 
<br /> 
<label for="Q2">Q2</label> 
<br /> 
<input id="GeneralQuestions_1__SelectedAnswerId" 
    name="GeneralQuestions[1].SelectedAnswerId" type="radio" value="11" /> 
<label for="A11">A11</label> 
<br /> 
<input id="GeneralQuestions_1__SelectedAnswerId" 
    name="GeneralQuestions[1].SelectedAnswerId" type="radio" value="12" /> 
<label for="A12">A12</label> 
<br /> 

而且爲了完整起見,這裏是模型的簡化版本中使用:

public class StudentViewModel 
{ 
    public List<Question> GeneralQuestions { get; set; } 
} 

public class Question 
{ 
    public int QuestionId { get; set; } 
    public string QuestionString { get; set; } 
    public ICollection<PossibleAnswer> PossibleAnswers { get; set; } 
    public int SelectedAnswerId { get; set; } 
} 

public class PossibleAnswer 
{ 
    public int Id { get; set; } 
    public string Answer { get; set; } 
} 

這裏是來自動作方法的代碼:

return View(new StudentViewModel 
{ 
    GeneralQuestions = 
     new List<Question> 
     { 
      new Question 
      { 
       QuestionString = "Q1", 
       PossibleAnswers = 
        new[] 
        { 
         new PossibleAnswer {Id = 1, Answer = "A01"}, 
         new PossibleAnswer {Id = 2, Answer = "A02"} 
        } 
      }, 
      new Question 
      { 
       QuestionString = "Q2", 
       PossibleAnswers = 
        new[] 
        { 
         new PossibleAnswer {Id = 11, Answer = "A11"}, 
         new PossibleAnswer {Id = 12, Answer = "A12"} 
        } 
      }, 
     } 
});