【问题标题】:MVC 5 and List of Complex typeMVC 5 和复杂类型列表
【发布时间】:2017-01-11 10:37:06
【问题描述】:

我查看了 MVC post a list of complex objectshttps://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。在其他部分,没有取值。

有什么想法吗?

【问题讨论】:

  • 您不能绑定到接口(@98​​7654329@ 不能初始化接口的实例)。你需要一个for 循环(或自定义EditorTemplate)——foreach 循环不起作用——请参阅this answer。您可以创建一个自定义 ModelBinder 来使用接口,但您还需要发布值来指示要初始化的具体实现
  • @StephenMuecke 因此,如果我将角色模型中的“List baseAttr”替换为“List baseAttr”,它应该可以工作吗?
  • 是的,只要您使用for 循环(或自定义EditorTempate 类型为BaseAttributes 并在主视图中使用@Html.EditorFor(m =&gt; m.baseAttr)
  • 所以我必须强烈键入我使用接口的每个地方,并在 for 循环中更改 foreach。好吧,这对接口来说有点糟糕:-/我会试试这个。
  • @StephenMuecke 好吧,我试过用它的实现替换接口的每一次出现:确实,表单采用了 ICaracteristic 的值,但它不再使用它的名字(- .-')。知道是什么原因造成的吗?

标签: asp.net-mvc list model-binding


【解决方案1】:

所以,既然斯蒂芬·穆克不在乎名誉:

--您不能将模型绑定到接口。

--你不能在列表上做foreach,因为modelbinder需要索引。

--您需要对要使用的每个值进行“控制”排序,因此对于复杂类型,您甚至需要在显示名称上进行排序。

一个好的解决方案是执行一个 for 循环,其中除了 @Html.DisplayFor 之外还包含一个 @Html.Hiddenfor,以便显示名称不可编辑但仍具有控件。 对于Interface和modelbinder缺乏交互,唯一的解决办法就是使用interface的实现。很遗憾。

【讨论】:

    猜你喜欢
    • 2013-12-15
    • 2012-09-16
    • 1970-01-01
    • 2014-10-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多