MVC CheckBox绑定回模型

时间:2017-03-21 14:47:56

标签: asp.net-mvc razor checkbox model-binding

所以我到处寻找这个特殊问题的答案,但我找不到确切的解决方案。很多类似的问题,但没有解决我的确切问题,所以如果已经得到答案,请道歉。

我有以下(简化)模型

public abstract class SimpleModel {
    public List<SimpleFieldModel> Fields{ get; set; }
}

public abstract class SimpleFieldModel {
    public List<ListItemModel> Items { get; set; }
}

public class ListItemModel {
     public string Text { get; set; }
     public string Value { get; set; }
     public bool Selected { get; set; }
}

使用以下 SimpleModel View

@for(var i = 0; i < Model.Fields.Count; i++) {
    @Html.EditorFor(Model.Fields[i])
}

以下 SimpleFieldModel查看

@for(var i = 0; i < Model.Items.Count; i++) {
    @Html.CheckBoxFor(m => Model.Items[i].Selected)
    @Html.HiddenFor(m => Model.Items[i].Text)
}

这会产生预期的标记

<input name="Fields[5].Items[0].Selected" id="Fields_5__Items_0__Selected" type="checkbox" value="true" data_val="89">
<input name="Fields[5].Items[0].Selected" type="hidden" value="false">
<input name="Fields[5].Items[0].Text" id="Fields_5__Items_0__Text" type="hidden" value="Option 1">

当这张贴到控制器时,我会收到以下内容:

  • form-data :Fields [5] .Items [0] .Selected =“true,false”
  • 模型:字段[5] .Items [0] .Selected = false

我必须编写一个方法来使用表单中的数据填充我的集合,但我觉得Razor应该为我照顾这个,但它似乎没有用。

修改

看起来根本原因可能是因为我期望在我的控制器中收到一个抽象模型,因为:

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(SimpleModel model)
{
}

为了解决这个问题,我有以下模型绑定器

public class SimpleModelBinder : DefaultModelBinder
{
    protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
    {
        var typeValue = bindingContext.ValueProvider.GetValue("ConcreteModelType");
        var type = Type.GetType(
            (string)typeValue.ConvertTo(typeof(string)),
            true
        );
        if (!typeof(SimpleModel).IsAssignableFrom(type))
        {
            throw new InvalidOperationException("Bad Type");
        }
        var model = Activator.CreateInstance(type);
        bindingContext.ModelMetadata = 
        ModelMetadataProviders.Current.GetMetadataForType(() => model, type);

        return model;
    }
}

奇怪的是,在退出上述活页夹时,模型具有正确数量的字段,并且每个字段都有正确的和预期的项目。但是,当我进入控制器方法时,我的模型似乎已被更改,因为它现在缺少字段中的项目。

我为最初不包含所有代码而道歉,但我无法提供对完整代码库的访问权。

进一步更新

我认为提及我也有一个 SimpleFieldModelBinder 也可能是相关的。就是这样:

public class SimpleFieldModelBinder : DefaultModelBinder
{
    protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
    {
        var typeValue = bindingContext.ValueProvider.GetValue(string.Format("{0}.{1}", bindingContext.ModelName, "ConcreteFieldModelType"));
        var type = Type.GetType(
            (string)typeValue.ConvertTo(typeof(string)),
            true
        );
        if (!typeof(SimpleFieldModel).IsAssignableFrom(type))
        {
            throw new InvalidOperationException("Bad Type");
        }
        var model = Activator.CreateInstance(type);

        bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => model, type);

        return model;
    }
}

因此,当我退出SimpleModelBinder时,我拥有所有字段,并且它们具有正确的项目(尽管未绑定到最近的表单更改)。然而,我的控制器似乎正在接收缺少相关项列表的SimpleFieldModel对象列表。

SimpleFieldModelBinder肯定出了问题。如果我把它拿出来,我的 SimpleModel 包含一个抽象 SimpleFieldModel 对象的列表。但是,如果我将其保留,控制器会在其“字段”列表中接收到具有正确具体类型的 SimpleModel ,但这些都已清除其

另一次更新

我在SimpleFieldModelBinder中添加了一些代码,以便从表单数据中填充Items集合。退出CreateModel时,集合完好无损(并且具有适当的Selected值)。然而,当我到达我的控制器(我必须假设它是绑定的下一步?)这些项目集合已被删除。但有一点可疑的是,第一个字段 其项目已就位,但所有其他字段都没有。我怀疑绑定只适用于Fields集合中的第一个项目,即使在调试期间,我点击所有字段的SimpleFieldModelBinder。

我可能会遗失什么?

谢谢

1 个答案:

答案 0 :(得分:1)

请将其复制到Visual Studio中。这应该对你有帮助。

控制器/模型

public class HomeController : Controller
{
    public class SimpleModel
    {
        public List<ListItemModel> Items { get; set; }
    }

    public class ListItemModel
    {
        public string Text { get; set; }
        public string Value { get; set; }
        public bool Selected { get; set; }
    }

    [HttpPost]
    public ActionResult Index29(SimpleModel sm)
    {
        //put breakpoint here to interrogate passed in model
        return View();
    }

    public ActionResult Index29()
    {
        ListItemModel lim = new ListItemModel { Selected = false, Text = "aText", Value = "aValue" };
        ListItemModel limTwo = new ListItemModel { Selected = true, Text = "bText", Value = "bValue" };
        SimpleModel sm = new SimpleModel();
        sm.Items = new List<ListItemModel>();
        sm.Items.Add(lim);
        sm.Items.Add(limTwo);

        return View(sm);
    }

查看:

@model Testy20161006.Controllers.HomeController.SimpleModel
@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Index29</title>
</head>
<body>
    <div>
        @using (Html.BeginForm())
        {

            for (var i = 0; i < Model.Items.Count; i++)
            {
                @Html.Label(Model.Items[i].Text)

                //modify the next line
                @Html.CheckBoxFor(
                    m => Model.Items[i].Selected)

                @Html.HiddenFor(m => Model.Items[i].Text)
                @Html.HiddenFor(m => Model.Items[i].Value)
            }

            <input type="submit" value="Post" />
        }
    </div>
</body>
</html>