我有以下模型结构:
表格>表单部分> FormQuestions> FormQuestionOptions(选项用于下拉列表/单选按钮列表中的选项)。
我已经构建了用于创建和编辑Form,FormSection,FormQuestion ok的视图。
现在我想创建一个视图,它将根据传递的表单ID动态生成表单实例。我可以为FormInstance生成表单控件,但无法解决如何绑定基于FormQuestion模型生成的动态生成的控件。
`public class Form
{
public Form()
{
FormSections = new List<FormSection>();
}
[Required]
[Key]
public int FormId { get; set; }
[Required]
[MaxLength(255)]
public string Title { get; set; }
public bool Active { get; set; }
public List<FormSection> FormSections { get; set; }
}
public class FormSection
{
public FormSection()
{
FormQuestions = new List<FormQuestion>();
}
[Required]
[Key]
public int FormSectionId { get; set; }
[Required]
[Display(Name="Form")]
public int FormId { get; set; }
public virtual Form Form { get; set; }
[Required]
public string Title { get; set; }
[Required]
public int OrderById { get; set; }
public IList<FormQuestion> FormQuestions { get; set; }
}
public class FormQuestion
{
public FormQuestion()
{
FormQuestionOptions = new HashSet<FormQuestionOption>();
}
[Key]
[Required]
public int FormQuestionId { get; set; }
[Required]
[Display(Name ="Form Section")]
public int FormSectionId { get; set; }
public virtual FormSection FormSection { get; set; }
public string ControlName
{
get
{
return "q" + this.FormQuestionId.ToString();
}
}
[Required]
[Display(Name ="Control Type")]
public int ControlTypeId { get; set; }
public virtual ControlType ControlType { get; set; }
[Required]
[Display(Name = "Data Type")]
public int DataTypeId { get; set; }
public virtual DataType DataType { get; set; }
[Required]
public int OrderById { get; set; }
[Required]
public string Title { get; set; }
[DataType(System.ComponentModel.DataAnnotations.DataType.MultilineText)]
[Display(Name ="Additional Question Description")]
public string AdditionalDescription { get; set; }
[DataType(System.ComponentModel.DataAnnotations.DataType.MultilineText)]
public string HelpTip { get; set; }
public bool Mandatory { get; set; }
public bool Active { get; set; }
public string Answer {get; set; }
public ICollection<FormQuestionOption> FormQuestionOptions { get; set; }
}
public class FormQuestionOption
{
public int FormQuestionOptionId { get; set; }
[Required]
[Display(Name ="Form Question")]
public int FormQuestionId { get; set; }
public virtual FormQuestion FormQuestion { get; set; }
public string OptionText { get; set; }
}
`
在我的FormInstances.cs控制器中有一个GET和一个POST Create动作。如果存在模型错误,则应该POST POST操作 - 重新绑定用户在动态生成的控件中给出的答案。但是,我认为FormQuestion上的“答案”字段不在模型中的正确位置,因为在POST时,数据库中的“答案”始终为空白。
如何更改模型以便可以将Answer绑定到动态生成的表单控件?我怀疑答案属于FormInstance类的某个地方,而不是Form类?
`// GET: FormInstances/Create
public IActionResult Create(int formId)
{
Form frm = _context.Forms
.Include(f => f.FormSections)
.ThenInclude(fs => fs.FormQuestions)
.ThenInclude(fq => fq.FormQuestionOptions)
.Include(f => f.FormSections)
.ThenInclude(fs => fs.FormQuestions)
.ThenInclude(fq => fq.ControlType)
.Where(f => f.FormId == formId).First();
FormInstance fi = new FormInstance();
fi.FormId = formId;
fi.Form = frm;
return View(fi);
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("FormInstanceId,FormId,Surname,Forename,Address,PostCode,DOB,DateSubmitted")] FormInstance formInstance)
{
if (ModelState.IsValid)
{
// TODO: Write form data to text file
//_context.Add(formInstance);
//await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
// recreate the Form
Form frm = _context.Forms
.Include(f => f.FormSections)
.ThenInclude(fs => fs.FormQuestions)
.ThenInclude(fq => fq.FormQuestionOptions)
.Include(f => f.FormSections)
.ThenInclude(fs => fs.FormQuestions)
.ThenInclude(fq => fq.ControlType)
.Where(f => f.FormId == formInstance.FormId).First();
// set the FormInstance Form property
formInstance.Form = frm;
return View(formInstance);
}
`
我的观点 - /FormInstances/Create.cshtml
`
@for (int x = 0; x < Model.Form.FormSections.Count; x++)
{
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">@Model.Form.FormSections[x].Title</h3>
</div>
<div class="panel-body">
@for(int i = 0; i < Model.Form.FormSections[x].FormQuestions.Count; i++)
{
@if(Model.Form.FormSections[x].FormQuestions[i].ControlType.Title.ToLower() == "label")
{
<div class="alert alert-info">@Model.Form.FormSections[x].FormQuestions[i].Title</div>
}
else
{
<div class="form-group">
<label class="form-label" for="@Model.Form.FormSections[x].FormQuestions[i].ControlName">@Model.Form.FormSections[x].FormQuestions[i].Title</label>
@if(!String.IsNullOrEmpty(Model.Form.FormSections[x].FormQuestions[i].AdditionalDescription))
{
<div> @Html.Raw(Model.Form.FormSections[x].FormQuestions[i].AdditionalDescription) </div>
}
@switch(Model.Form.FormSections[x].FormQuestions[i].ControlType.Title.ToLower())
{
case "textbox":
<input type = "text" asp-for="@Model.Form.FormSections[x].FormQuestions[i].Answer" class="form-control" required="@(Model.Form.FormSections[x].FormQuestions[i].Mandatory == true ? "required" : "")" />
break;
case "textbox multiline":
<textarea asp-for="@Model.Form.FormSections[x].FormQuestions[i].Answer" rows="5" class="form-control"></textarea>
break;
case "drop down list":
<select asp-for="@Model.Form.FormSections[x].FormQuestions[i].Answer" class="form-control">
<option value = "" > ---Please Select ---</option>
@foreach(FormQuestionOption fqo in Model.Form.FormSections[x].FormQuestions[i].FormQuestionOptions)
{
<option> @fqo.OptionText </option>
}
</select>
break;
case "radio button list":
foreach (FormQuestionOption fqo in Model.Form.FormSections[x].FormQuestions[i].FormQuestionOptions)
{
<p>
<input type = "radio" asp-for="@Model.Form.FormSections[x].FormQuestions[i].Answer" value="@fqo.OptionText" />
@fqo.OptionText
</p>
}
break;
case "checkbox":
<input type="checkbox" for="Form.FormSections[@x].FormQuestions[@i].@Model.Form.FormSections[x].FormQuestions[i].Answer" />
break;
default:
<div class="alert alert-warning">Unknown Control Type</div>
break;
}
</div>
}
}
</div>
</div>
}
`
修改 对不起,这是我在webforms之后的第一个MVC项目。感谢您的反馈意见。我在下面创建了一个新的模型结构。 1)继承TextQuestion,YesNoQuestion和MultipleChoiceQuestion的Question类是否有效? 2)我可以通过OrderById属性来命令TextQuestion,YesNoQuestion和MultipleChoiceQuestion的混合,还是会搞乱模型绑定的索引?我是否需要将3个问题列表合并到父列表中?这将如何影响使用EditorFor的能力?
`
public class Form
{
public int FormId { get; set; }
public string Title { get; set; }
public List<FormSection> Sections { get; set; }
}
public class FormSection
{
public int FormSectionId { get; set; }
public int FormId { get; set; }
public string Title { get; set; }
public int OrderById { get; set; }
public List<TextQuestion> TextQuestions { get; set; }
public List<YesNoQuestion> YesNoQuestions { get; set; }
public List<MultipleChoiceQuestion> MultipleChoiceQuestions { get; set; }
}
public class Question
{
public int QuestionId { get; set; }
public int FormSectionId { get; set; }
public string Title { get; set; }
public string HelpTip { get; set; }
public bool Active { get; set; }
public bool Mandatory { get; set; }
public int OrderById { get; set; }
}
public class TextQuestion : Question
{
public string TextAnswer { get; set; }
}
public class YesNoQuestion : Question
{
public bool? YesNoAnswer { get; set; }
}
public class MultipleChoiceQuestion : Question
{
public List<MultipleChoiceOption> MultipleChoiceOptions { get; set; }
public int? SelectedMultipleChoiceOptionId { get; set; }
}
public class MultipleChoiceOption
{
public int MultipleChoiceOptionId { get; set; }
public string Value { get; set; }
}
// need to display:
// Form.Title
// Each FormSection.Title,
// Each TextQuestion, YesNoQuestion, MultipleChoiceQuestion needs displaying
// along with the appropriate control for receiving an answer, therefore also need:
// also FormSection.TextQuestions, FormSection.YesNoQuestions, FormSection.MulitpleChoiceQuestions
// which will enable to use:
// TextQuestion.Title, TextQuestion.HelpTip, TextQuestion.TextAnswer, TextQuestion.Mandatory
// YesNoQuestion.Title, YesNoQuestion.HelpTip, YesNoQuestion.YesNoAnswer
// MultipleChoiceQuestion.Title, MultipleChoiceQuestion.HelpTip, MultipleChoiceQuestion.Mandatory, MultipleChoiceOption.MultipleChoiceOptions, MultipleChoiceQuestion.SelectedMultipleChoiceOptionId,
// Also additional fields (DateSubmitted and SubmittedBy) that are required for all forms
public class FormInstanceVM
{
public int FormId { get; set; }
public string FormTitle { get; set; }
public List<FormSection> Sections { get; set; }
public List<TextQuestion> TextQuestions { get; set; }
public List<YesNoQuestion> YesNoQuestions { get; set; }
public List<MultipleChoiceQuestion> MultipleChoiceQuestions { get; set; }
public DateTime DateSubmitted { get; set; }
public string SubmittedBy { get; set; }
}
// controller
// /FormInstances/Create
[HttpGet]
public ActionResult Create(int formId)
{
// get form and its sections and questions from database
// create a FormInstanceVM using the Form object and return the VM
}
// /FormInstances/Create
[HttpPost]
public ActionResult Create(FormInstanceVM fi)
{
// get form data from ViewModel passed from form
}
`