【发布时间】:2017-01-11 10:37:06
【问题描述】:
我查看了 MVC post a list of complex objects 和 https://mhwelander.net/2014/03/26/asp-net-mvc-model-binding-not-occurring-when-posting-list-of-complex-types/ 以及其他一些关于该主题的帖子。
我还是更愿意问这个问题,以便理解而不是简单地复制粘贴答案。
我有一个复杂的类型如下:
public interface ICaracteristic
{
int value { get; set; }
int max { get; set; }
string name { get; set; }
}
public class BaseAttributes : ICaracteristic
{
public int max { get; set; }
public int value { get; set; }
public string name { get; set; }
Random r = new Random();
}
以及使用这些类型的多个列表的对象:
public class Character
{
// Infos
public string characterName { get; set; }
public string playerName { get; set; }
public IGame game { get; set; }
// Caracteristics
public List<ICaracteristic> baseAttr { get; set; }
public List<ICaracteristic> skills { get; set; }
public List<ICaracteristic> stats { get; set; }
public List<ICaracteristic> spendPoints { get; set; }
}
我省去了构造函数和其他一些方法。
现在,为了创建,我只是要求我的用户输入角色和玩家的名字,没问题,因为这些都是简单的字符串,所以效果很好。
对于编辑,我在“我的数据库”中获取字符(基于 xml 表,但在这里无关紧要),并以这种方式显示:
@model RPGmvc.Models.Character
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
<h4>Character @Html.TextBoxFor(model => model.characterName)</h4>
<hr />
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
<div class="row">
<!--SECTION BASE ATTRIBUTES-->
<div class="col-md-3">
<!-- @foreach (var item in Model.baseAttr)
{
<div>
<label>@Html.DisplayFor(model => item.name)</label>
<p>@Html.EditorFor(model => item.value, new { @class = "form-control" })</p>
</div>
}
对于显示,这非常好:它显示了我角色的每个基本属性的正确名称和值(以及其他列表的值)。
但是,当我单击表单下方的“保存”按钮时,发布的模型会重置该列表的值...但不会重置 characterName。
奇怪的是,它似乎混合了该模型的不同构造函数:我没有在我的编辑模板中使用的 playerName 设置为“托比确定”(就像在我的空基本构造函数中一样),但是 characterName是正在编辑的当前字符之一,而不是“新字符”(如在所述构造函数中)
我尝试使用 for 而不是 foreach,认为列表中的索引可能有助于传递正确的值;但是因为我使用的接口给出了错误“无法创建接口实例”。
我尝试过使用自定义编辑器,但它产生了与“foreach”相同的问题。
(这是自定义编辑器,以防万一:
@model RPGmvc.Models.Caracteristic.ICaracteristic
<p>
@Html.DisplayFor(m => m.name)
@Html.DisplayFor(m => m.value)
</p>
请注意,使用接口作为模型不会导致任何问题。 )
我知道我显然可以通过我的页面添加大量注释来对此进行排序,但由于自定义编辑器不起作用,for with index 也不起作用,我首先想解释一下正在发生的事情:
这里的模型绑定器会发生什么? 我可以“强迫”他创建我的接口实现的实例,而不是接口本身吗? HttpPost 怎么会创建一个混合了我的构造函数的自定义对象?
感谢您的帮助。
编辑:Stephen Muelcke 建议从我的模型中删除接口并使用真实的实现来帮助我。这几乎奏效了:
现在我的 Post 采用 BaseAttributes 的正确值,但它们的名称是“null”。 这是有问题的,因为我的数据来自 XML 表,我以这种方式搜索:
foreach (ICaracteristic battr in myCharac.baseAttr)
{
var currentNode = myDoc.SelectSingleNode("/character_sheet/base_attributes/" + battr.name.Replace(" ", "_").ToLower());
currentNode.InnerText = battr.value.ToString();
}
这显然失败了,因为名称是“null”。
我只在“基本属性”部分中将“foreach”更改为“for”。在该部分中,所有名称都设置为 null。在其他部分,没有取值。
有什么想法吗?
【问题讨论】:
-
您不能绑定到接口(@987654329@ 不能初始化接口的实例)。你需要一个
for循环(或自定义EditorTemplate)——foreach循环不起作用——请参阅this answer。您可以创建一个自定义ModelBinder来使用接口,但您还需要发布值来指示要初始化的具体实现 -
@StephenMuecke 因此,如果我将角色模型中的“List
baseAttr”替换为“List baseAttr”,它应该可以工作吗? -
是的,只要您使用
for循环(或自定义EditorTempate类型为BaseAttributes并在主视图中使用@Html.EditorFor(m => m.baseAttr) -
所以我必须强烈键入我使用接口的每个地方,并在 for 循环中更改 foreach。好吧,这对接口来说有点糟糕:-/我会试试这个。
-
@StephenMuecke 好吧,我试过用它的实现替换接口的每一次出现:确实,表单采用了 ICaracteristic 的值,但它不再使用它的名字(- .-')。知道是什么原因造成的吗?
标签: asp.net-mvc list model-binding