【问题标题】:MVC Add and remove items from subcollectionMVC 从子集合中添加和删除项目
【发布时间】:2012-09-05 20:52:52
【问题描述】:

我无法将数据绑定到集合项的集合(我也无法正确表述我的问题)。让我们通过使用 psudo 模型的示例让每个人都更轻松。

假设我有以下示例模型:

public class Month()
{
    public int ID { get; set; }
    public string Name { get; set; }
    public virtual ICollection<Week> Weeks { get; set; }
}

public class Week()
{
    public int ID { get; set; }
    public int MonthID { get; set; }
    public String Name { get; set; }
    public virtual ICollection<Day> Days { get; set; }
}

public class Day()
{
    public int ID { get; set; }
    public String Name { get; set; }
}

...和一个示例视图模型:

public class EditMonthViewModel()
{
    public Month Month { get; set; }
    public List<Week> Weeks { get; set; }
    public List<Day> AllDays { get; set; }
}

编辑操作/视图的目的是使用户能够编辑一个月、分配给该月的周数,以及从某个月的周数中添加和删除天数。视图可能会有所帮助。

@model myProject.ViewModels.EditMonthViewModel

//...
@using (Html.BeginForm())
{
    //Edit Month Stuff...

    @for(int i = 0; i < Model.Weeks.Count(); i++)
    {
        <h2>@Model.Weeks[i].Name</h2>
        @Html.EditorFor(model => Model.Weeks[i].Name)

        //loop through all possible days
        //Select only days that are assigned to Week[i] 
        @for(int d = 0; d < Model.AllDays.Count(); d ++)
        {
            //This is the focus of this question.  
            //How do you bind the data here?
            <input type="checkbox"
                   name="I have no idea" 
                   @Html.Raw(Model.Weeks[i].Days.Contains(Model.AllDays[d]) ? "checked" : "") />
        }
    }
}

控制器动作方法

public ActionResult Edit(int id)
{
    var viewModel = new EditMonthViewModel();
    viewModel.Month = db.Months.Find(id);
    viewModel.Weeks = db.Weeks.Where(w => w.MonthID == id).ToList();

    viewModel.AllDays = db.Days.ToList();
}

[HttpPost]
public ActionResult Edit(EditMonthViewModel viewModel)
{
    var monthToUpdate = db.Months.Find(viewModel.Month.ID);
    //...

    if(viewModel.Weeks != null)
    {
        foreach (var week in viewModel.Weeks)
        {
            var weekToUpdate = monthToUpdate.Weeks.Single(w => w.ID == week.ID);
            //...

            /*So, I have a collection of weeks that I can grab, 
              but how do I know what was selected? My viewModel only has a 
              list of AllDays, not the days selected for Week[i]
            */
        }
}

如何确保在我提交表单时选定的日期将绑定到星期?

【问题讨论】:

  • 您遇到了什么问题/错误?我们可以看到您处理此表单帖子的控制器操作吗?
  • 我也有兴趣查看填充您的 ViewModel 的控制器操作。有趣的是,您的 Month 类已经引用了 Weeks 并间接引用了 Days(通过 Weeks),但您已将这些作为额外字段添加到 ViewModel 中。为什么?
  • 我添加了一些伪动作方法。我是 MVC 的新手,我遵循的理念是视图不应运行查询(在视图模型中发送视图所需的一切)。如果您认为不需要,那么我当然可以换个方式。我的主要问题(我无法表达)是我不知道复选框的“名称”属性需要是什么才能让模型活页夹分配日期。我将添加另一个小段更好地解释这种情况。
  • RE“在视图模型中发送视图所需的一切” - 您已经通过为视图模型提供Month 属性来完成此操作。 Month 类有一个 Week 集合,而后者又具有一个 Day 集合。无需为 ViewModel 提供这些集合的额外副本。
  • 关于如何将视图输入绑定到视图模型字段的问题,这篇文章解释了如何有效地做到这一点。 stackoverflow.com/questions/5700558/… 要点是您不应该在视图中使用循环,而是使用 editorTemplates。

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


【解决方案1】:

看起来最简单的做法是让表单以填充IEnumerable&lt;DayModel&gt; 类型的数据结构为目标,其中DayModel 定义为:

public class DayModel
{
    public int WeekId { get; set; }
    public int DayId { get; set; }
    public bool IsIncluded { get; set; }
}

您可以在大多数情况下保持 Razor 代码不变,但是在渲染复选框时,您可以执行以下操作:

@{
    var modelIdx = 0;
}

// ...

<input type="hidden" name="days[@modelIdx].WeekId" value="@Model.Weeks[i].Id" />
<input type="hidden" name="days[@modelIdx].DayId" value="@Model.AllDays[d].Id" />
<input type="checkbox" name="days[@modelIdx].IsIncluded" value="@(Model.Weeks[i].Days.Contains(Model.AllDays[d]) ? "checked" : "")" />
@{ modelIdx++; }

然后,您发布到的控制器操作可能具有此签名:

[HttpPost]
public ActionResult Edit(IEnumerable<DayModel> days)
{
    //...
}

对我有帮助的是永远不要混淆视图模型,它应该只用于视图模型(通常是 GET 操作)和非视图模型(我们称之为普通模型)。避免让您的 POST 操作尝试绑定到视图模型,这将大大简化您的生活。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-03
    • 1970-01-01
    • 1970-01-01
    • 2023-04-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多