简体   繁体   English

MVC 5通用列表绑定到局部视图

[英]MVC 5 Generic List Binding to Partial View

I'm having an issue with the bindings of my model to a partial view and feel that there must be a way to do what I want. 我在将模型绑定到局部视图时遇到问题,觉得必须有一种方法可以做我想做的事情。 I wonder if my design is flawed and a small refactoring might be necessary. 我想知道我的设计是否有缺陷,是否需要进行少量重构。

A very simplified (and abstract) version of my models would be like so: 我的模型的非常简化(抽象)版本如下所示:

Public Class BaseClass
{
    Public string Name { get; set; }
    Public List<SomeClass> Things { get; set; }
}

Public Class DerivedClass : BaseClass
{
    Public List<LineItem> Items { get; set; }
}

Public Class Library
{
    Public List<LineItem> Items { get; set; }
}

Public Class LineItem
{
    Public string Name { get; set; }
    Public string Value { get; set; }
}

I have Editor Templates for the BaseClass, SomeClass, and LineItem. 我有BaseClass,SomeClass和LineItem的编辑器模板。 These are shown in the view for DerivedClass and work as intended by submitting changes to the controller. 这些显示在DerivedClass的视图中,并通过将更改提交给控制器来按预期工作。 The LineItem template is wrapped in a LineItemList partial view because I intend to use it for a view for Library and don't want to repeat all of that layout and javascript. LineItem模板包装在LineItemList局部视图中,因为我打算将其用于Library的视图,并且不想重复所有这些布局和javascript。 The LineItemList partial view is included on the DerivedClass view by Html.PartialView since there doesn't seem to be a way to create an Editor Template for the List type. Html.PartialView将LineItemList局部视图包括在DerivedClass视图中,因为似乎没有办法为List类型创建编辑器模板。 So my views look like this: 所以我的观点看起来像这样:

  • DerivedClassView DerivedClassView
    • BaseClassPartialView BaseClassPartialView
      • SomeClassPartialView SomeClassPartialView
    • LineItemListPartialView LineItemListPartialView
      • LineItemParialView LineItemParialView

When I submit my form, the controller gets all of the data for the BaseClass and SomeClass list but none for the LineItem list. 当我提交表单时,控制器将获取BaseClass和SomeClass列表的所有数据,但LineItem列表的所有数据均不会。 The difference of course being that one is rendered using Html.EditorFor and the other Html.PartialView. 当然不同之处在于,一个是使用Html.EditorFor和另一个Html.PartialView呈现的。

Refactoring the classes will be tough as they have to be backwards compatible with an old XML format for serialization, but I'm sure I can work some magic if necessary. 重构类将很困难,因为它们必须与旧的XML格式向后兼容才能进行序列化,但是我敢肯定,如有必要,我可以做一些魔术。

As Chris Pratt mentioned, I forgot to include my controller methods: 正如克里斯·普拉特(Chris Pratt)所述,我忘了包括我的控制器方法:

Public ActionResult DerivedClassEditor()
{
    Return View(New DerivedClass());
}

[HttpPost]
Public ActionResult DerivedClassEditor(DerivedClass dc)
{
    // Do Stuff
}

I just noticed in the rendered Html, the SomeClass controls are named SomeClass.[0].Name while those of the LineItem are [0].Name . 我刚刚在呈现的HTML中注意到,SomeClass控件被命名为SomeClass.[0].Name而LineItem的控件则是[0].Name I have a feeling that might be a symptom of the issue. 我觉得这可能是问题的征兆。

And my views look similar to this: 我的看法与此类似:

DerivedClassEditor DerivedClassEditor

@model DerivedClass

@using (Html.BeginForm())
{
    @Html.EditorFor(model => model)

    @Html.Partial("LineItemListPartialView")

    <input type="submit" />
}

LineItemListPartialView LineItemListPartialView

@model List<LineItem>

<div name="Items">
    @Html.EditorFor(model => model)
</div>

LineItemPartialView LineItemPartialView

@model LineItem

<div name="LineItem">
    @Html.LabelFor(model => model.Name)
    @Html.TextEditorFor(model => model.Name)
</div>

Edit : 编辑

A link to my view: https://github.com/melance/TheRandomizer/blob/Initial/TheRandomizer.WebApp/Views/UserContent/AssignmentEditor.cshtml 指向我的视图的链接: https : //github.com/melance/TheRandomizer/blob/Initial/TheRandomizer.WebApp/Views/UserContent/AssignmentEditor.cshtml

I've narrowed down the issue to the fact that when I load one of the lists using @Html.EditorFor it names the inputs Collection[index].Property yet when I add one dynamically using the same call it simply names the input Property . 我已将问题缩小为以下事实:当我使用@ Html.EditorFor加载列表之一时,它将输入命名为Collection[index].Property而当我使用相同的调用动态添加一个列表时,它仅将输入Property命名。 Is there an easy and reusable way to have the addition of new items have the same naming structure? 是否有一种简单且可重用的方式来使新项目的添加具有相同的命名结构?

Crucially, you failed to post your controller code, so I'm stabbing in the dark, but I think I can guess pretty well what's happening. 至关重要的是,您未能发布您的控制器代码,所以我在暗中st刺,但我想我可以很好地猜测发生了什么。 You most likely have something like: 您最有可能遇到以下情况:

[HttpPost]
public ActionResult MyAwesomeAction(BaseClass model)
{
    ...
}

And you're assuming that since your view is working with DerivedClass and posting DerivedClass that you should end up with an instance of DerivedClass rather than BaseClass in your action. 并且您假设由于视图正在使用DerivedClass并发布DerivedClass ,因此您应该在操作中使用DerivedClass实例而不是BaseClass结束。 That assumption is incorrect. 该假设是不正确的。

All that exists on post is a set of string key-value pairs. 发布时仅存在一组字符串键值对。 The modelbinder looks at the action signature and attempts to bind the posted data to an instance of the parameter(s), newing up classes as necessary. 模型绑定器查看动作签名,并尝试将发布的数据绑定到参数实例,并根据需要更新类。 Given this, the only information the modelbinder has in this scenario is that it's expected to bind values to an instance of BaseClass and a set of data to attempt to do that with. 鉴于此,在这种情况下,modelbinder拥有的唯一信息是可以将值绑定到BaseClass实例和一组数据以尝试执行此操作。 As a result, it will create an instance of BaseClass and bind what data it can, dropping anything it can't. 结果,它将创建BaseClass的实例并绑定它可以绑定的数据,删除所有不能绑定的数据。 Importantly, since BaseClass doesn't include stuff like your Items property, all of that data will be discarded. 重要的是,由于BaseClass不包含诸如Items属性之类的东西,因此所有这些数据都将被丢弃。

Long and short, polymorphism isn't supported with action parameters. 总而言之,动作参数不支持多态。 The type of your parameter must be the type you want. 参数的类型必须是所需的类型。 Period. 期。

For what it's worth, you can use editor templates for list properties. 对于它的价值,您可以将编辑器模板用于列表属性。 EditorFor will simply render the editor template for the contained type for each item in the list. EditorFor会简单地为列表中每个项目呈现所包含类型的编辑器模板。 For example, calling: 例如,调用:

@Html.EditorFor(m => m.Items)

Is essentially the same as: 基本上与:

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

So after much research, trial and error and help from Erik, I was able to solve my problem. 因此,经过Erik的大量研究,反复试验和帮助,我得以解决我的问题。 The issue turned out to be the naming of the form elements in my partial view. 问题出在我的局部视图中是表单元素的命名。 When added by the model they are indexed as such: name = "ListProperty[Index].PropertyName" . 当由模型添加时,它们的索引如下: name = "ListProperty[Index].PropertyName" When I was adding my partial views using ajax, the were named for just the Property Name. 当我使用ajax添加局部视图时,它们仅以属性名称命名。 In order to fix this, I had to handle my ajax calls for the partial view like this: 为了解决这个问题,我不得不像这样处理局部视图的ajax调用:

public ActionResult CreateParameter(Int32 index)
{
    ViewData.TemplateInfo.HtmlFieldPrefix = $"Parameters[{index}]";
    return PartialView("~/Views/Shared/EditorTemplates/Configuration.cshtml");
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM