ASP.NET Core

时间:2017-11-30 15:53:37

标签: c# asp.net asp.net-mvc model-binding

我有以下模型结构:

表格>表单部分> 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
}
`

0 个答案:

没有答案