我想我会在这里写一些东西,因为我尝试了接受的答案并最终遇到了编译问题 - 我不了解你们,但 DictionaryTest[index].Key 行对我不起作用 -从什么时候开始数组访问需要Key 属性?!
对于其他寻找答案的人来说,有一些技巧可以让这一切像魔术一样工作。简而言之,这一切都取决于:
为了将多个属性绑定到一个对象(可以是任何复杂类型的列表或字典),模型绑定器需要知道哪些属性属于组合在一起 - 否则纠缠不清。
假设你有一个这样的类型:
public class TestClass
{
public string Prop1 { get; set; }
public string Prop2 { get; set; }
}
你希望它绑定到这样的方法中:
public ActionResult MyAction(List<TestClass> test)
{
...
}
如果你只是像这样在页面上转储一堆输入:
<input name="Prop1" value="FirstP1" />
<input name="Prop2" value="FirstP2" />
<input name="Prop1" value="SecondP1" />
<input name="Prop2" value="SecondP2" />
模型绑定器如何知道哪些是在一起的?简短的回答:它没有 - 它需要一点帮助。您可能已经知道,关键是给它相关的索引,以便它可以确定要分组的索引:
<input name="test[0].Prop1" value="FirstP1" />
<input name="test[0].Prop2" value="FirstP2" />
<input name="test[1].Prop1" value="SecondP1" />
<input name="test[1].Prop2" value="SecondP2" />
现在模型绑定器可以将前两个 [0] 组合在一起,将接下来的两个 [1] 组合在一起,瞧,我们有一个列表绑定。
注意: 资深人士会记得,重要的是您的索引保持有序 - 如果它们最终不完整或无序(例如,您最终得到 [0]、[3]、 [1] 由于某些客户端删除或排序),那么您将面临麻烦,因为模型绑定器会按顺序查找。您可以通过添加一些客户端 JS 来解决此问题,以便在表单保存时按顺序重新分配名称 - 这很有效。或者您可以继续阅读:
字典呢?
了解上述内容后,绑定字典实际上非常简单:因为它们实际上只是 List<KeyValuePair<X,Y>>:
<input name="test[0].Key" value="Item1" />
<input name="test[0].Value" value="Item1Value" />
<input name="test[1].Key" value="Item2" />
<input name="test[1].Value" value="Item2Value" />
但是,如果您提交的索引是无序的,则同样的问题/限制也适用。这里的一个特定场景是 checkboxes - 如果您有一个 Dictionary<string, bool>(或任何其他键类型)要绑定为复选框,您会记得 HTML 不会在表单中提交未选中的复选框提交。因此,如果您只勾选几个项目,您最终会得到一个部分列表,其中的索引保证是无序的。
解决方案1:在提交表单之前在客户端做JS事情来重写索引,强制它们是顺序的。完全可行,但很烦人。
解决方案 2:使用乱序键,帮助模型绑定器了解要查找的键。这很简单:你只需要一个额外的输入来定义索引:
<input type="hidden" name="test.Index" value="IndexA" />
<input name="test[IndexA].Key" value="IndexAKey" />
<input name="test[IndexA].Value" value="IndexAValue" />
<input type="hidden" name="test.Index" value="SomeOtherIndex" />
<input name="test[SomeOtherIndex].Key" value="SomeOtherIndexKey" />
<input name="test[SomeOtherIndex].Value" value="SomeOtherIndexValue" />
名称为<collectionName>.Index 的额外输入为模型绑定器提供了将其全部整理出来所需的轻推。对于字典,使用字典键作为自定义索引很方便,这样所有内容都可以对齐 - 感觉有点多余,但确实有效:
<input type="hidden" name="test.Index" value="IndexAKey" />
<input name="test[IndexAKey].Key" value="IndexAKey" /> //<-- totally feel like this line doesn't need to be there, but it works
<input name="test[IndexAKey].Value" value="IndexAValue" />
完整地说,Dictionary[index].Key 的符号完全是需要发生的——但这应该是一个 string,并且在 HTML 输入中是 name 属性——而不是在 Html.HiddenFor() 助手中。
大家安息吧!