【发布时间】:2017-08-13 07:34:42
【问题描述】:
所以我到处寻找这个特殊问题的答案,但我找不到确切的解决方案。很多类似的问题,但没有一个可以解决我的确切问题,如果已经回答,请道歉。
我有以下(简化的)模型:
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 视图:
@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">
当它发布到 控制器 时,我会收到以下信息:
- 表单数据:Fields[5].Items[0].Selected = "true,false"
- 模型:Fields[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 对象列表,这些对象缺少相关的 Items 列表。
SimpleFieldModelBinder 肯定有问题。如果我把它拿出来,我的 SimpleModel 包含抽象 SimpleFieldModel 对象的列表。但是,如果我把它留在里面,控制器会收到一个 SimpleModel,在其 Fields 列表中具有正确的具体类型,但这些都被清除了它们的 Items。
另一个更新
我在 SimpleFieldModelBinder 中添加了一些代码,以便它从表单数据中填充 Items 集合。在退出 CreateModel 时,集合是完整的(并且具有适当的 Selected 值)。然而,当我到达我的控制器时(我必须假设这是绑定的下一步?)这些 Items 集合已被删除。不过,有点可疑的是,第一个字段 有其项目,但所有其他字段都没有。我怀疑绑定仅适用于 Fields 集合中的第一项,即使在调试期间,我为所有字段都点击了 SimpleFieldModelBinder。
我可能缺少什么?
谢谢
【问题讨论】:
-
你到底在期待什么?
-
您的 POST 方法只需要一个参数
SimpleModel model(即匹配您传递给视图的模型)并且Items属性将与每个Selected和Text属性正确绑定(您不为Value创建表单控件,因此该属性将为null,并且不清楚您为什么要这样做new { data_val = Model.Items[i].Value }) -
但是您的代码不会生成该 html - 它不会有
Fields[5]前缀 - 它将只是name="Items[0].Selected"除非您还没有向我们展示其他内容 -
完全正确。我的模型更复杂。我将尝试添加更多内容以帮助解释情况。谢谢。
-
@Oxonhammer。如果您的 POST 方法有一个参数
SimpleModel model,那么model将与您表单中的值正确绑定。 (并且是@Html.EditorFor(m => m.Model.Fields)为您的集合中的所有项目生成正确的 html - 没有循环)
标签: asp.net-mvc razor checkbox model-binding