ViewModel与Razor View的数据绑定然后将POST ViewModel发送到Controller

时间:2014-05-12 16:43:51

标签: c# asp.net-mvc entity-framework razor

更新帖子

我目前正在开发一个使用MVC4,Razor,EF5的Survey应用程序。将有各种调查,将使用一种观点。应用程序的模型来自现有数据库。除此之外,我为以下内容创建了一个单独的实体:

SurveyDisplay - 将显示在调查页面上的元素的模型,因为它包含不同的语言。

SurveyInfo - 数据来自网络服务的信息模型。

SurveyQuestion - 调查问卷的模型。

SurveyChoices - 调查中每个问题的选择模型。

SurveyAnswers - 用于检索答案选择的模型

更新图片(已添加SurveyAnswers)

请参阅以下图片,了解以下字段: enter image description here

我可以在我的页面中显示特定值,这是一个Razor,但在POST时。我得到ModelState.IsValid == false。除SurveyAnswers外,所有模型均为null。

enter image description here

enter image description here

以下是我的代码到目前为止的情况:

SurveyRepository: 对于这部分,我导入了存储过程以从数据库中获取数据。

    public List<SurveyQuestion> GetQuestions(int surveyid)
    {
        using (var ctx = new ICSDBContext())
        {
            return ctx.GetSurveyQuestions(surveyid).ToList<SurveyQuestion>();
        }
    }
    public List<SurveyChoice> GetChoices(int surveyid)
    {
        using (var ctx = new ICSDBContext())
        {
            return ctx.GetSurveyChoices(surveyid).ToList<SurveyChoice>();
        }
    }
    public List<SurveyDisplay> GetSurveyDisplay(int surveyid)
    {
        using (var ctx = new ICSDBContext())
        {
            return ctx.GetSurveyDisplay(surveyid).ToList<SurveyDisplay>();
        }
    }

SurveyController:

using ICS.Repositories;
using ICS.ViewModels;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

public class SurveyController : Controller
{
    SurveyRepository surveyRepository = new SurveyRepository();
    SurveyViewModel surveyViewModel = new SurveyViewModel();

    [HttpGet]
    public ActionResult Index(int surveyid, string rowid)
    {
        var surveyDisplay = surveyRepository.GetSurveyDisplay(surveyid);
        var surveyQuestions = surveyRepository.GetQuestions(surveyid);
        var surveyChoices = surveyRepository.GetChoices(surveyid);

        string headerText = "";
        string messageBody = "";
        string buttonText = "";

        foreach (var item in surveyDisplay)
        {
            headerText = item.HeaderText;
            messageBody = item.MessageBody;
            buttonText = item.ButtonText;
        }
            surveyViewModel.HeaderText = Server.HtmlEncode(headerText);
            surveyViewModel.MessageBody = Server.HtmlEncode(messageBody);
            surveyViewModel.Buttontext = Server.HtmlEncode(buttonText);
            surveyViewModel.SurveyQuestions = surveyQuestions;
            surveyViewModel.SurveyChoices = surveyChoices;

        return View("Survey", surveyViewModel); 
    }

//Not the actual code yet. I'm trying to check in this action whether there is POSTed data or none. 
[HttpPost]

}

SurveyViewModel

public class SurveyViewModel
{
    public List<SurveyInfo> SurveyInfo { get; set; }
    public string HeaderText { get; set; }
    public string MessageBody { get; set; }
    public string Buttontext { get; set; }
    public List<SurveyQuestion> SurveyQuestions { get; set; }
    public List<SurveyChoice> SurveyChoices { get; set; }
    public List<SurveyAnser> SurveyAnsers { get; set; }
}

Razor查看

<h2>@Html.DisplayFor(model => model.HeaderText)</h2>
    <div id="info">
        <p>@Html.DisplayFor(model => model.MessageBody)</p>
        <div class="margTop20">
            <ul>
                @for (var info = 0; info < Model.SurveyInfo.Count(); info++)
                {
                    <li>
                        <span>Case ID: </span>
                        <b>@Html.DisplayFor(model => model.SurveyInfo[info].SRNumber)</b>
                    </li>
                    <li>
                        <span>Description: </span>
                        <b>Others</b>
                    </li>
                    <li>
                        <span>Problem Category: </span>
                        <b>@Html.DisplayFor(model => model.SurveyInfo[info].ProblemSubCategory)</b>
                    </li>
                    <li>
                        <span>Product: </span>
                        <b>@Html.DisplayFor(model => model.SurveyInfo[info].Product)</b>
                    </li>
                    <li>
                        <span>Method of Service: </span>
                        <b>@Html.DisplayFor(model => model.SurveyInfo[info].SupportType)</b>
                    </li>
                }
            </ul>
        </div>
    </div>
    @for (var question = 0; question < Model.SurveyQuestions.Count(); question++)
    {
        <div id="@("question" + ConvertNumberToWords.Translate(question))" class="@(Convert.ToBoolean(Model.SurveyQuestions[question].Subquestion) == true ? "subquestion" : "questions")">
            <p>
                <b>
                    @Html.DisplayFor(model => model.SurveyQuestions[question].TheQuestion)
                </b>
            </p>
            @Html.HiddenFor(model => model.SurveyAnswers[question].QuestionID)
            @if (Convert.ToBoolean(Model.SurveyQuestions[question].Mandatory) == true)
            {
                <p><span id="@("errorQuestion" + ConvertNumberToWords.Translate(question))" class="errorMsg">*Please choose your answer</span></p>
            }
            @for (var choice = 0; choice < Model.SurveyChoices.Count(); choice++)
            {
                if (Model.SurveyQuestions[question].QuestionID == Model.SurveyChoices[choice].QuestionID)
                {
                    if (Model.SurveyChoices[choice].isStyleOptBox)
                    {
                        var choicesGroup = (from c in Model.SurveyChoices where c.QuestionID == Model.SurveyQuestions[question].QuestionID select new { c.ChoicesID, c.ChoicesName });
                        @Html.Raw("<ul>")
                        @Html.Raw("<li>")
                        @Html.RadioButtonForSelectList(model => model.SurveyAnswers[question].ChoiceID, new SelectList(choicesGroup, "ChoicesID", "ChoicesName"))
                        @Html.Raw("</li>")
                        @Html.Raw("</ul>")
                        break;
                    }
                    else if (Model.SurveyChoices[choice].isStyleChkBox)
                    {
                        var choicesGroup = (from c in Model.SurveyChoices where c.QuestionID == Model.SurveyQuestions[question].QuestionID select new { c.ChoicesID, c.ChoicesName });
                        @Html.Raw("<ul>")
                        @Html.Raw("<li>")
                        @Html.CheckBoxListFor(model => model.SurveyAnswers[question].ChoiceID, model => choicesGroup, model => model.ChoicesID, model => model.ChoicesName, model => false, Position.Vertical)
                        @Html.Raw("</li>")
                        @Html.Raw("</ul>")
                        break;
                    }
                    else if (Model.SurveyChoices[choice].isStyleCboBox)
                    {

                    }
                    else
                    {
                      <div class="margTop20">
                        <p>
                            @*<textarea cols="" rows="5" class="form-control"></textarea>*@
                            @Html.TextAreaFor(model => model.SurveyAnswers[question].Comment, new { rows = "5", cols = "0", @class = "form-control" })
                        </p>
                      </div>
                    }
                }
            }
        </div>
    }
</div>
<input id="hidQuestionCount" type="hidden" value="@Model.SurveyQuestions.Count()" />

<div>
    @*<a class="btn btn-primary" href="#myModal" id="btnSubmit">@Model.Buttontext</a> @Url.Action("Submit", "SaveSurvey", Model)*@
    <input id="btnSubmit" class="btn btn-primary" type="submit" value="@Model.Buttontext" />
</div>

如果您注意到,我正在使用自定义Html Helper来渲染RadioButtonSelectListFor的单选按钮组,这在这种情况下非常方便。我可以绑定并获取所选控件的值,如下图所示:

enter image description here

其次,我还使用Html Helper包Hmtl Helper CheckBoxListFor来显示一组复选框,以进行多项选择并提交。但问题是,我在所有复选框中获得1个值,这让我真正感到痛苦和头痛。如果选中了2个或更多复选框,则只返回第一个项目,您可以参考下图:

enter image description here

对于评论值,我没有问题,因为我可以得到值。如图所示:

enter image description here

我也有一个问题,我需要在SurveyAnswers中绑定QuestionID,因为它用于报告目的。

总而言之,以下是我要实现的目标:

目的:

  1. 将QuestionID绑定到SurveyAnswers模型
  2. 返回所有复选框值并将其添加到列表SurveyAnswers
  3. 如果可能,请将ModelState.IsValid设为true。如果没有,我不会验证模型以获取SurveyAnwsers列表
  4. 我真的想让这件事情发挥作用。我一直在做很多研究,只是为了让它继续下去,但还没有进展。请帮助我们!任何意见/建议都将受到高度赞赏。

    非常感谢!

1 个答案:

答案 0 :(得分:2)

问题在于您的视图模型中的这些行:

public List<SurveyInfo> SurveyInfo { get; set; }
...
public List<SurveyQuestion> SurveyQuestions { get; set; }
public List<SurveyChoice> SurveyChoices { get; set; }

由于您引用了完整实体(可能每个实体都有自己需要的属性),因此您需要确保每个必需属性都以某些值回发,否则会使整个模型无效,因为该实体无效。但是,您实际上并不是创建任何这些实体,而只是显示现有实例。因此,您也应该为每个使用视图模型。您的视图模型或视图模型引用的任何内容都应该是唯一需要的是您要从用户收集的实际数据。

<强>更新

这是关于模型绑定器如何工作以及它如何确定模型是否有效的全部内容。它看起来好像你想将整个东西保存到数据库中,好像你有一个与你的视图模型相匹配的表(即使你实际上并不是这样)。因此,为了使视图模型有效且&#34;,它必须能够保存视图模型上的所有其他内容(您的SurveyInfoSurveyQuestions和{ {1}}属性。如果在这些类中有任何必需的属性,那么不会回发(当然有),那么它们就是无效的,并且您的视图模型无效结果。现在,那就是条件。只是因为你附上SurveyChoices列表并不意味着你必须在你的POST中有一个有效的SurveyQuestions个实例列表body允许视图模型验证。如果列表或关系是SurveyQuestion,那么它验证(假设列表或实例本身不是必需的)。所以,真的,你在这里出错的地方是发回这些事情的部分实例。因为它最终会列出一个不完整的null实例列表,所以&#39 ; s无效,而如果您根本没有发回任何内容,有效。

换句话说,您可以按原样保留列表,在视图中提取信息,,您需要在其他地方附加POST数据。创建另一个列表属性,如:

SurveyQuestion

这就是你发布的唯一内容。然后,只要用户按照public List<SurveyAnswerViewModel> SurveyAnswers { get; set; } 中的定义正确填写调查,您就拥有了有效的视图模型。请注意,由于您未发布其他列表,因此如果需要返回视图以纠正错误,则必须重新填充它们。