说明
嵌套对象需要绑定到下拉列表,嵌套对象已经有一个预选值。可能的值为枚举类型。包含一些其他数据的下拉列表将回发到控制器。
代码 - 类型和类:
[Serializable]
public enum DummyEnum
{
DummyZero = 0,
DummyOne = 1
}
public class Dummy
{
public Guid Id { get; set; }
public Dictionary<Guid, DummyEnum> DummyEnum { get; set; }
}
public class DummyViewModel
{
public Dictionary<Guid, List<Dummy>> Dummies { get; set; }
}
public class DummyController
{
private void Init(DummyViewModel model)
{
model.EnumList = Enum.GetValues(typeof(DummyEnum))
.Cast<DummyEnum>()
.Select(e => new SelectListItem
{
Value = (e).ToString(),
Text = e.ToString()
});
}
}
HTML:
<td>
@Html.DropDownListFor(
m => m.Dummies[dummiesKey][dummyIndex]
.Enum[Id],
new SelectList(Model.EnumList, "Value", "Text", e.ToString()))
</td>
<select
data-val="true"
data-val-required="The Enum field is required."
id="Dummies_guid__0__Enum_guid_"
name="Dummies[guid][0].Enum[guid]"
style="display: none;"
>
<option value="DummyOne">DummyOne</option>
<option selected="selected" value="DummyZero ">DummyZero</option>
</select>
问题
问题是模型似乎无法将有效负载映射回对象,或者错过了对绑定对象的引用。所有内容都正确填写了枚举的 guid、索引和值。
有效载荷:
Dummies[guid][0].Enum[guid]: DummyZero
Dummies[guid][0].Enum[guid]: DummyZero
尝试
我尝试了以下想法,但它们对我来说并不成功。
- 模型未绑定到字典
- 绑定字典
我错过了什么?
问题中所述的问题与 mvc 将Dictionary
转换为 ListJSON
有关。
所有需要做的是像 mvc 一样分解对象并提供必要的数据。如分词装订中所述。
对象类型为Dictionary<Guid, List<Dummy>>
。所以对象实际上变得List<KeyValuePair<Guid, List<List<KeyValuePair<Guid, enum>>>>>
。
现在分解一下
MVC 需要正在使用的第一个对象的索引。为了获得这个索引,我们需要将字典隐藏到我们自己的列表中。更具体的字典的值或键。
var dummies= Model.Dummies[key];
var dummiesIndex = Model.Dummies.Values.ToList().IndexOf(dummies);
索引需要与帖子一起提供。这可以通过在字典中的键旁边将其作为隐藏字段添加到下拉列表上方来完成。
@Html.Hidden("dummies.Index", dummiesIndex)
@Html.Hidden("dummies[" + dummiesIndex + "].Key", key)
接下来是对象列表。同样,需要为绑定提供索引。
@Html.Hidden("dummies[" + dummiesIndex + "].Value.Index", dummyIndex)
最后一步是另一本字典,这就像第一本字典
一样@Html.Hidden("dummies[" + dummiesIndex + "].DummyEnum.Index", dummyEnumIndex)
@Html.Hidden("dummies[" + dummiesIndex + "].DummyEnum.Key", yourKey)
对于您要实际发布的值,您需要遵循上述完整路径。
@Html.DefaultCombo("dummies[" + dummiesIndex + "].DummyEnum[" + dummyEnumIndex+ "]", "Value", "Text", Model.EnumList, enum)
现在,MVC 可以重新映射您的对象。
前端响应将采用您在此处设置的形式。然后,ASP 中间件会将所有这些字符串解析回后端的对象。
所以这里的关键时刻是:
- 控制器操作参数类型 - 它可以是您的任何类型,但它应该与您的前端相关;
- 前端的
select
元素name
属性值 - 它应包含完整的现有路径。
正如我从您的代码示例中得到的,如下所示。
- 您有
DummyViewModel
视图模型类。它具有属性Dummies
。 - 您有
Dummy
类,该类嵌套在DummyViewModel
中,作为Dummies
。 二级词典。 - 您有
DummyEnum
枚举类,该类正在使用DummyEnum
值。相同的名称,不同的相邻级别。 - 选择列表值正常。它们直接来自枚举。
- 根据结构,要设置第一个枚举值,您需要通过设置 KEY 和 VALUE 来导航其级别。然后再做一次,进入另一个级别。对我来说,这个结构中的第一个枚举值应该是这样的:
Dummies[dummiesKeyGuid][dummyIndexId].DummyEnum[dummyEnumKeyGuid];
每个步骤中都有以下类型:
Dummies[dummiesKeyGuid]
<List<Dummy>>
;Dummies[dummiesKeyGuid][dummyIndexId]
是<Dummy>
;Dummies[dummiesKeyGuid][dummyIndexId].DummyEnum[dummyEnumKeyGuid]
是<DummyEnum>
.
因此,应更新@Html.DropDownListFor(...)
以将路径设置为name
.
也:
- 操作应将
Dummies
类型作为参数。
ActionResult SomeFromProcessingAction(DummyViewModel Dummies)
- 您应该处理传递给
Dictionary
类型的字符串化参数映射。它可以在ASP(前端)之外使用,但存在问题。请检查这篇文章及其主题:https://stackoverflow.com/a/29820891/6344916。有时,在那里不使用Dictionary
更容易。只是其他类,如列表或数组。
从您的 HTML 示例中,我没有获得在其结构中包含Enum
字段的m.Dummies
类型。dummiesKey
不可能有"guid"
价值。GUID 是另一种可以轻松ToString()
但不能以其他方式制作的类型。
恕我直言。名称中的Dummy
太多。它混淆并破坏了它的理解。
此外,它的嵌套结构非常繁琐。您可以使用较小的用户窗体来设置值,并在后端获取较小的对象或事件值,而不是使用较大的对象参数。
List 类没有映射要求,只需对字典进行非规范化,映射它们会更容易。他们在前端的导航也是如此。如果需要,您可以将列表设置为ToDictionary()
。:)=)
例如,可以使用List<T>
编写Dummy
:
public class SomeElement
{
public Guid Id { get; set; }
public DummyEnum Enum { get; set; }
}
public class Dummy //kind of aggregation
{
public Guid Id { get; set; }
public List <SomeElement> DummyEnum { get; set; }
}
等等DummyViewModel
.或者摆脱它并直接使用一些列表。
希望这会有所帮助。
我认为您的问题与嵌套属性或输入命名无关,您的实现似乎很好。
您遇到的问题链接到Dictionary<Guid, ...>
默认模型绑定程序行为。默认的活页夹似乎根本无法正确处理它。(即。以Guid
为键的词典)
我已经重现了您的问题,然后切换到Dictionary<string, ...>
这次一切正常。
您可以克服此问题的唯一方法可能是实现您自己的模型绑定器Dictionary<Guid, object>
。
我试图了解根本问题,它似乎位于此处(从字符串到 Guid 的无效显式强制转换),此处也描述了(稍后发现:-)...