MVC 5:模型中的字典绑定到视图中的一系列复选框?

时间:2017-05-23 13:37:27

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

当我将模型发送到控制器进行保存时,控制器会获得一个空字典。

出了什么问题?绑定工作有什么特别之处吗?

我的模特有这个属性:

public Dictionary<int, bool> DictionaryTest { get; set; }

我的控制器在调用视图之前填充一些数据:

mymodel.DictionaryTest = new Dictionary<int, bool> { { 0, false }, { 1, true }, { 2, false } };

我的观点使用以下代码正确显示:

@Html.CheckBoxFor(m_ => m_.DictionaryTest[0], new { @class = "form-control" })
@Html.CheckBoxFor(m_ => m_.DictionaryTest[1], new { @class = "form-control" })
@Html.CheckBoxFor(m_ => m_.DictionaryTest[2], new { @class = "form-control" })

非常感谢

2 个答案:

答案 0 :(得分:1)

要绑定字典,您需要具有以下内容的值:DictionaryProperty[N].KeyDictionaryProperty[N].Value。因此,您的Razor代码需要看起来像:

@Html.HiddenFor(m_ => m_.DictionaryTest[0].Key)
@Html.CheckBoxFor(m_ => m_.DictionaryTest[0].Value, new { @class = "form-control" })

@Html.HiddenFor(m_ => m_.DictionaryTest[1].Key)
@Html.CheckBoxFor(m_ => m_.DictionaryTest[1].Value, new { @class = "form-control" })

@Html.HiddenFor(m_ => m_.DictionaryTest[2].Key)
@Html.CheckBoxFor(m_ => m_.DictionaryTest[2].Value, new { @class = "form-control" })

但是,如果您的键是整数,则字典过度。只需使用一个简单的列表。然后,您的Razor代码将按原样运行。

答案 1 :(得分:1)

我以为我在这里写点什么,因为我尝试了接受的答案并最终得到了汇编问题 - 而且我不了解你们,但是DictionaryTest[index].Key行只是没有& #39;为我工作 - 因为数组访问何时需要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]组合在一起,并且我们有一个列表绑定。

注意:那里的退伍军人会记得,你的指数保持秩序很重要 - 如果他们最终不完整或无序(例如你最终得到{{1} },[0][3]由于某些客户端删除或排序)然后您将面临麻烦,因为模型绑定器按顺序查看。您可以通过添加一些客户端JS来解决这个问题,以便在表单保存时按顺序重新分配名称 - 这样可以解决问题。或者你可以继续阅读:

字典怎么样?

一旦你理解了上述内容,让字典绑定实际上非常简单:假设它们只是[1]

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" /> (或任何其他键类型)绑定为复选框,则您会回想起HTML没有&#39;在表单提交中提交未选中的复选框。因此,如果您只勾选一些项目,最终会得到一个部分列表,其中保证索引不合规定。

解决方案1:在表单提交之前,让JS客户端重写索引,强制它们是顺序的。完全可行,但很烦人。

解决方案2:使用无序键,帮助模型绑定器了解要查找的键。这很简单:你只需要一个额外的输入来定义索引:

Dictionary<string, bool>

名为<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,并且在HTML输入string属性中 - 而不是name帮助者。

和平外出的人们!