显示对象列表并为每个输入 MVC 设置值字段

Display list of objects and set a value field for each input MVC

我将以下 class 定义为我的 ViewModel

 public class CreateApplicationViewModel
    {
        public Step1ViewModel Step1 { get; set; }
        public Step2StandAloneViewModel Step2StandAlone { get; set; }
        public Step2ChildViewModel Step2Child { get; set; }
        public Step3ViewModel Step3 { get; set; }
        public Step4ViewModel Step4 { get; set; }
    }

我正在尝试在 Step4ViewModel 中显示项目,其中包含以下内容:

 public class Step4ViewModel
    {
        public List<DataDetails> DataDetails = new List<DataDetails>();

    }

public class DataDetails
    {
        public string GroupCode { get; set; }
        public string GroupDesc { get; set; }
        public decimal DetailSequence { get; set; }
        public string DetailCode { get; set; }
        public string DetailDesc { get; set; }
        public string YesNoFlag { get; set; }
        public string NumberFlag { get; set; }
        public string ValueFlag { get; set; }
        public string DateFlag { get; set; }
        public string ListValuesFlag { get; set; }
        public string CommentFlag { get; set; }
        public string CalcRateFlag { get; set; }
        public string ColumnSequence { get; set; }
        public string TextFlag { get; set; }
        public string CheckboxFlag { get; set; }
        public string YesNoValue { get; set; }
        public int NumberValue { get; set; }
        public DateTime DateValue { get; set; }
        public string ListValue { get; set; }
        public string CommentValue { get; set; }
        public string TextValue { get; set; }
        public bool CheckboxValue { get; set; }
    }

在我的控制器中,我像这样填充 Step4ViewModel.DataDetails:

private Step4ViewModel GetCaseDataDetails(string caseType)
        {
            Step4ViewModel model = new Step4ViewModel();

            List<DataDetails> data = new List<DataDetails>();
            List<DataDetailsValues> values = new List<DataDetailsValues>();

            var dataDetails = (from tb1 in db.DEFAULT_CASE_DATA_VW
                               join tb2 in db.CASE_DATA_DETAIL on tb1.CASE_DATA_GROUP_ID equals tb2.CASE_DATA_GROUP_ID
                               where tb1.BUS_CASE_CODE == caseType
                               orderby tb2.DETAIL_SEQUENCE
                               select new { tb1, tb2 });


            foreach (var detail in dataDetails.ToList())
            {
                DataDetails i = new DataDetails();
                DataDetailsValues j = new DataDetailsValues();
                i.CalcRateFlag = detail.tb2.CALC_RATE_FLAG;
                i.CheckboxFlag = detail.tb2.CHECKBOX_FLAG;
                i.ColumnSequence = detail.tb2.COLUMN_SEQUENCE;
                i.CommentFlag = detail.tb2.COMMENT_FLAG;
                i.DateFlag = detail.tb2.DATE_FLAG;
                i.DetailCode = detail.tb2.DETAIL_CODE;
                i.DetailDesc = detail.tb2.DETAIL_DESC;
                i.DetailSequence = detail.tb2.DETAIL_SEQUENCE;
                i.GroupCode = detail.tb1.GROUP_CODE;
                i.GroupDesc = detail.tb1.GROUP_DESC;
                i.ListValuesFlag = detail.tb2.LIST_VALUES_FLAG;
                i.NumberFlag = detail.tb2.NUMBER_FLAG;
                i.TextFlag = detail.tb2.TEXT_FLAG;
                i.ValueFlag = detail.tb2.VALUE_FLAG;
                i.YesNoFlag = detail.tb2.YES_NO_FLAG;
                data.Add(i);
            }
            model.DataDetails = data;
            return model;
        }

我对 Step4ViewModel 的思考过程是,对于每个 DataDetail,我都会将 DetailDesc 显示为标签,然后在它旁边输入 NumberValue、YesOrNoValue、NumberValue、DateValue、ListValue、CommentValue、TextValue、或 CheckboxValue 取决于控件类型,然后 post 将该数据发送到服务器。我能够成功显示每个 DataDetail.DetailDesc,但对于每个输入,它也呈现,我输入输入的值永远不会 post 返回服务器。这是我的观点:

@model Portal.Models.ViewModel.CreateApplicationViewModel
@{
    ViewBag.Title = "Step 4/5";
    Layout = "~/Views/Shared/_Layout.cshtml";
}
@using System.Linq

<h4>Case Data Details</h4>

@using (Html.BeginForm("Step4", "CreateApplication", FormMethod.Post, new { @class = "col-sm-12" }))
{

    foreach (var group in Model.Step4.DataDetails.GroupBy(item => item.GroupDesc))
    {
        <div class="panel panel-primary">
            <div class="panel-heading">@Html.Encode(group.Key)</div>
            <div class="panel-body">

                @for (var i = 0; i < group.Count(); i++)
                { 
                    <div class="form-group">
                        <div class="row">
                            <div class="col-xs-6">
                                <label class="form-label">@Model.Step4.DataDetails[i].DetailDesc</label>
                            </div>
                            <div class="col-xs-6">
                                @if (Model.Step4.DataDetails[i].TextFlag == "Y")
                                {
                                    @Html.TextBoxFor(val => Model.Step4.DataDetails[i].TextValue, new { @class = "form-control" })
                                }
                                else if (Model.Step4.DataDetails[i].CheckboxFlag == "Y")
                                {
                                    @Html.CheckBoxFor(val => Model.Step4.DataDetails[i].CheckboxValue, new { @class = "checkbox" })
                                }
                            </div>
                        </div>
                    </div>
                }
            </div>
        </div>
    }
    <div class="col-sm-12">
        <div class="row">
            @Html.ActionLink("Cancel", "Welcome", "Home", null, new { @class = "btn btn-default" })
            <button class="btn btn-default" onclick="history.go(-1);">Previous</button>
            <button type="submit" class="btn btn-default">Next</button>
        </div>
    </div>

post 数据

的控制器
[HttpPost] 
public ActionResult Step4(Step4ViewModel step4) 
{ 
    if (ModelState.IsValid) 
    { 
        CreateApplicationViewModel model = (CreateApplicationViewModel)Session["case"]; 
        // model.Step4 = step4; 
        Session["case"] = model; 
        return View(); 
    } 
    return View(); 
}

我在想这可能是由于分组,我这样做是为了将每个组分成一个单独的 HTML 面板元素,但我的输入是用名称中的索引号呈现的。任何有关更好的方法来完成此任务的帮助或建议将不胜感激。干杯!

更新

这是我更新的 post 控制器和视图:

@model Portal.Models.ViewModel.CreateApplicationViewModel
@{
    ViewBag.Title = "Step 4/5";
    Layout = "~/Views/Shared/_Layout.cshtml";
}
@using System.Linq

<h4>Case Data Details</h4>

@using (Html.BeginForm("Step4", "CreateApplication", FormMethod.Post, new { @class = "col-sm-12" }))
{

    int index = 0;
    foreach (var group in Model.Step4.DataDetails.GroupBy(item => item.GroupDesc))
    {
        <div class="panel panel-primary">
            <div class="panel-heading">@Html.Encode(group.Key)</div>
            <div class="panel-body">

                <input type="hidden" name="Step4.DataDetails.Index" value="@index" />

                @for (var i = 0; i < group.Count(); i++)
                {
                    <div class="form-group">
                        <div class="row">
                            <div class="col-xs-6">
                                <label class="form-label">@Model.Step4.DataDetails[i].DetailDesc</label>
                            </div>
                            <div class="col-xs-6">
                                @if (Model.Step4.DataDetails[i].TextFlag == "Y")
                                {
                                    @Html.TextBoxFor(val => val.Step4.DataDetails[i].TextValue, new { @class = "form-control" })
                                }
                                else if (Model.Step4.DataDetails[i].CheckboxFlag == "Y")
                                {
                                    @Html.CheckBoxFor(val => val.Step4.DataDetails[i].CheckboxValue, new { @class = "checkbox" })
                                }
                            </div>
                        </div>
                    </div>
                }
            </div>
        </div>
        index++;
    }
    <div class="col-sm-12">
        <div class="row">
            @Html.ActionLink("Cancel", "Welcome", "Home", null, new { @class = "btn btn-default" })
            <button class="btn btn-default" onclick="history.go(-1);">Previous</button>
            <button type="submit" class="btn btn-default">Next</button>
        </div>
    </div>
}


[HttpPost]
        public ActionResult Step4(CreateApplicationViewModel step4)
        {
            if (ModelState.IsValid)
            {
                CreateApplicationViewModel model = (CreateApplicationViewModel)Session["case"];
               // model.Step4 = step4;
                Session["case"] = model;
                return View();
            }
            return View();
        }

更新 2

如果我将 FormCollection 传递给 HttpPost 控制器,我就可以获得表单输入。关于为什么我可以获得这些值作为 FormCollection 而不是模型的任何想法?

您正在 post 列出复杂对象。但是 MVC DefaultModelBinder 无法绑定到您的 DataDetails 对象,因为当 post 对包含复杂对象列表的表单进行索引时,索引必须按顺序排列。在您的情况下,由于嵌套的 for 循环,此序列被破坏。所以你可以做的是采用一个单独的变量并像这样使用默认值 0 初始化 - 我已经尝试修改你的代码。

@using (Html.BeginForm("Step4", "CreateApplication", FormMethod.Post, new { @class = "col-sm-12" }))
{

    int index = 0;
    foreach (var group in Model.Step4.DataDetails.GroupBy(item => item.GroupDesc))
    {
        <div class="panel panel-primary">
            <div class="panel-heading">@Html.Encode(group.Key)</div>
            <div class="panel-body">

                <input type="hidden" name="Step4.DataDetails.Index" value="@index" />

                @for (var i = 0; i < group.Count(); i++)
                { 
                    <div class="form-group">
                        <div class="row">
                            <div class="col-xs-6">
                                <label class="form-label">@Model.Step4.DataDetails[i].DetailDesc</label>
                            </div>
                            <div class="col-xs-6">
                                @if (Model.Step4.DataDetails[i].TextFlag == "Y")
                                {
                                    @Html.TextBoxFor(val => val.Step4.DataDetails[i].TextValue, new { @class = "form-control" })
                                }
                                else if (Model.Step4.DataDetails[i].CheckboxFlag == "Y")
                                {
                                    @Html.CheckBoxFor(val => val.Step4.DataDetails[i].CheckboxValue, new { @class = "checkbox" })
                                }
                            </div>
                        </div>
                    </div>
                }
            </div>
        </div>
        index++;
    }
    <div class="col-sm-12">
        <div class="row">
            @Html.ActionLink("Cancel", "Welcome", "Home", null, new { @class = "btn btn-default" })
            <button class="btn btn-default" onclick="history.go(-1);">Previous</button>
            <button type="submit" class="btn btn-default">Next</button>
        </div>
    </div>
}

看看我在视图中添加的隐藏字段。这对 post 你的数据有好处,即使序列被破坏了。希望对你有帮助。

通过使用索引整数并从上面的答案递增它并在我看来以不同的方式实现该想法,我能够将模型返回给控制器:

@model Portal.Models.ViewModel.CreateApplicationViewModel
@{
    ViewBag.Title = "Step 4/5";
    Layout = "~/Views/Shared/_Layout.cshtml";
}
@using System.Linq

<h4>Case Data Details</h4>

@using (Html.BeginForm("Step4", "CreateApplication", FormMethod.Post, new { @class = "col-sm-12" }))
{
    int index = 0;
    foreach (var group in Model.Step4.DataDetails.GroupBy(item => item.GroupDesc))
    {

        <div class="panel panel-primary">
            <div class="panel-heading">@Html.Encode(group.Key)</div>
            <div class="panel-body">
                @for (var i = 0; i < group.Count(); i++)
                {
                    <div class="form-group">
                        <div class="row">
                            <div class="col-xs-6">
                                <label class="form-label">@Model.Step4.DataDetails[i].DetailDesc</label>
                            </div>
                            <div class="col-xs-6">
                                @Html.TextBoxFor(val => val.Step4.DataDetails[index].TextValue)
                                @Html.HiddenFor(val => val.Step4.DataDetails[index].GroupCode)
                            </div>
                        </div>
                    </div>
                    index++;
                }

            </div>
        </div>
    }
    <div class="col-sm-12">
        <div class="row">
            @Html.ActionLink("Cancel", "Welcome", "Home", null, new { @class = "btn btn-default" })
            <button class="btn btn-default" onclick="history.go(-1);">Previous</button>
            <button type="submit" class="btn btn-default">Next</button>
        </div>
    </div>
}

视图中的上述代码为我提供了每个元素的正确索引,并允许我 post