当ListBox为空时,永远不会调用该属性的setter

时间:2013-07-30 21:23:30

标签: c# asp.net-mvc

我有如下财产:

    [DisplayName("Children")]
    public List<long> ChildrenIds
    {
        get { return SelectedGroup.Children.Select(x => x.Id).ToList(); }
        set
        {
            foreach (long groupId in value)
            {
                if (groupId != 0 && !SelectedGroup.Children.Select(x => x.Id).Contains(groupId))
                {
                    var group = FactoryTools.Factory.Get<GroupLookup>(groupId);

                    if (group != null) SelectedGroup.AddChild(group);
                }
            }

            var childrenLooper = SelectedGroup.Children.ToList();
            foreach (var group in childrenLooper)
            {
                if (group.Id != 0 && !value.Contains(group.Id))
                {
                    SelectedGroup.Children.Remove(group);
                }
            }
        }
    }

当我在标准Razor Listbox中选择了至少一个孩子时,这很有效:

    <div class="oneThird">
        @Html.LabelFor(x => x.ChildrenIds)
        @Html.ListBoxFor(x => x.ChildrenIds, ListHelper.GetGroupsMinusSelf(Model.SelectedGroup))
        @Html.ValidationMessageFor(x => x.ChildrenIds)
    </div>

但是,当我取消选择上面ListBox中的所有项目时,此属性的setter永远不会被调用,因此这些项目永远不会被删除...什么是确保所有项目的最佳方法这些物品被删除了吗?

1 个答案:

答案 0 :(得分:2)

如果没有选择任何项目,则没有从浏览器发布的数据,并且ASP.NET MVC模型绑定没有值设置。

换句话说,模型活页夹说:“我没有设置的价值,所以我打电话给设定者是没有意义的”,而你期望它说:“我没有价值设置,但无论如何我都会用一个空列表给Serj的setter打电话“。

但真正的问题在于,您正在推动模型绑定超出其设计目标。模型绑定只是将HTTP请求中数据的字符串表示形式转换为强类型数据。因此,您绑定到的模型应该表示HTML表单或类似简单的东西(是的,我知道Microsoft吹嘘您可以开箱即用模型绑定到复杂对象,但这只适用于最简单的情况,TBH )。一旦数据被强类型化,请在您的操作方法(或业务对象,服务,帮助程序或其他)中进行数据处理。

我建议你

1)像MyForm类那样引入类似的东西:

public class MyForm 
{ 
  public IEnumerable<int> ChildrenIds { get;set; }
}

2)引入一个类似的视图模型:

public class MyViewModel 
{
  public MyViewModel(Data somedata)
  {
    /* populate Options */
  }

  public IEnumerable<SelectListItem> Options { get; set; }
  public MyForm Form { get; set; }
}

3)在您的视图中使用此模型:

@Html.ListBoxFor(m => m.Form.ChildrenIds, Model.Options)

4)最后,对于你的动作方法,你建模绑定到MyForm:

public ActionResult MyMethod(MyForm form)
{
  /* inspect POSTed form.ChildrenIds, add/remove from domain model etc. as you see fit */
}

这将使您更清楚地将HTTP问题与业务问题分开。