![](/img/trans.png)
[英]MVC3 passing dictionary values to dropdownlist and binding associated key to the model
[英]MVC3 Dictionary not binding to model
我有一个包含字典属性的模型。 (这已从一个较大的项目中提炼到此示例中,我已经确认仍然存在相同的问题)
public class TestModel
{
public IDictionary<string, string> Values { get; set; }
public TestModel()
{
Values = new Dictionary<string, string>();
}
}
控制器
public class TestController : Controller
{
public ActionResult Index()
{
TestModel model = new TestModel();
model.Values.Add("foo", "bar");
model.Values.Add("fizz", "buzz");
model.Values.Add("hello", "world");
return View(model);
}
[HttpPost]
public ActionResult Index(TestModel model)
{
// model.Values is null after post back here.
return null; // I set a break point here to inspect 'model'
}
}
和一个视图
@using TestMVC.Models
@model TestModel
@using (Html.BeginForm())
{
@Html.EditorFor(m => m.Values["foo"]);
<br />
@Html.EditorFor(m => m.Values["fizz"]);
<br />
@Html.EditorFor(m => m.Values["hello"]);
<br />
<input type="submit" value="submit" />
}
这样呈现给浏览器:
<input class="text-box single-line" id="Values_foo_" name="Values[foo]" type="text" value="bar" />
我遇到的问题是回发后字典在模型上为空。
我需要某种键值存储,因为表单上的字段是可变的,所以我不能使用POCO模型。
通读Scott hanselman关于该主题的博客文章以了解更多详细信息,但与此同时,为了解决您的问题,只需将您的视图替换为以下内容:
<input type="hidden" name="Values[0].Key" value="foo" />
<input type="text" name="Values[0].Value" value="bar" />
对所有部分重复相同的操作,也许将其放入for循环中,例如:
@for(i=0;i<Model.Values.Count;i++)
{
@Html.Hidden("Values[@i].Key", @Model.Values.Keys[@i])
@Html.TextBox("Values[@i].Value", @Model.Values.Values[@i])
}
请注意,仅当使用OrderedDictionary时,才可以通过索引访问键和值
Scott hanselman展示了如何对字典进行ModelBinding
引用博客
如果签名看起来像这样:
public ActionResult Blah(IDictionary<string, Company> stocks) { // ... }
我们用HTML给出了这个:
<input type="text" name="stocks[0].Key" value="MSFT" /> <input type="text" name="stocks[0].Value.CompanyName" value="Microsoft Corporation" /> <input type="text" name="stocks[0].Value.Industry" value="Computer Software" /> <input type="text" name="stocks[1].Key" value="AAPL" /> <input type="text" name="stocks[1].Value.CompanyName" value="Apple, Inc." /> <input type="text" name="stocks[1].Value.Industry" value="Consumer Devices" />
http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx
@model Dictionary<string, string>
@for (int i = 0; i < 3; i++)
{
Html.EditorFor(m => m[i].Value)
{
我认为它也可以通过按键来工作,例如
Html.EditorFor(m => m.Values["foo"].Value)
如果您需要绑定一个Dictionary,以使每个值都有一个texbox进行编辑,则下面是一种使其起作用的方法。 影响表达式如何在HTML中生成的真正重要的部分是模型表达式,这是确保模型绑定在回发时发生的原因。 本示例仅适用于字典。
链接的文章介绍了使绑定起作用的HTML语法,但是保留Razor语法来完成此工作还是一个谜。 同样,本文的不同之处在于它们允许编辑键和值,并且使用整数索引,即使字典的键是字符串而不是整数也是如此。 因此,如果您要绑定一个Dictionary,那么在决定采用哪种方法之前,您真的需要首先评估是只希望Values是可编辑的,还是只希望Key和Values是可编辑的,因为这些情况大不相同。
如果您需要绑定到复杂的对象(例如Dictionary),则应该只需要为每个属性创建一个文本框,表达式就可以钻入该属性,类似于本文。
public class SomeVM
{
public Dictionary<string, string> Fields { get; set; }
}
public class HomeController : Controller
{
[HttpGet]
public ViewResult Edit()
{
SomeVM vm = new SomeVM
{
Fields = new Dictionary<string, string>() {
{ "Name1", "Value1"},
{ "Name2", "Value2"}
}
};
return View(vm);
}
[HttpPost]
public ViewResult Edit(SomeVM vm) //Posted values in vm.Fields
{
return View();
}
}
CSHTML:
仅用于值的编辑器 (当然,您可以添加LabelFor以基于键生成标签):
@model MvcApplication2.Controllers.SomeVM
@using (Html.BeginForm()) {
@Html.ValidationSummary(true)
<fieldset>
<legend>SomeVM</legend>
@foreach(var kvpair in Model.Fields)
{
@Html.EditorFor(m => m.Fields[kvpair.Key]) //html: <input name="Fields[Name1]" …this is how the model binder knows during the post that this textbox value gets stuffed in a dictionary named “Fields”, either a parameter named Fields or a property of a parameter(in this example vm.Fields).
}
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
编辑两个键/值:
@{ var fields = Model.Fields.ToList(); }
@for (int i = 0; i < fields.Count; ++i)
{
//It is important that the variable is named fields, to match the property name in the Post method's viewmodel.
@Html.TextBoxFor(m => fields[i].Key)
@Html.TextBoxFor(m => fields[i].Value)
//generates using integers, even though the dictionary doesn't use integer keys,
//it allows model binder to correlate the textbox for the key with the value textbox:
//<input name="fields[0].Key" ...
//<input name="fields[0].Value" ...
//You could even use javascript to allow user to add additional pairs on the fly, so long as the [0] index is incremented properly
}
正如@Blast_Dan和@gprasant所提到的,模型绑定程序期望输入元素的name属性的格式为Property[index].Value
,其中index
是一个int
Value
而Value
是KeyValuePair
类的属性之一。
不幸的是, @Html.EditorFor
以错误的格式生成该值。 我编写了一个HtmlHelper扩展,以将name属性转换为正确的格式:
public static IHtmlString DictionaryEditorFor<TModel, TProperty, TKey, TValue>(this HtmlHelper<TModel> Html, Expression<Func<TModel, TProperty>> expression, IDictionary<TKey, TValue> dictionary, DictionaryIndexRetrievalCounter<TKey, TValue> counter, string templateName, object additionalViewData)
{
string hiddenKey = Html.HiddenFor(expression).ToHtmlString();
string editorValue = Html.EditorFor(expression, templateName, additionalViewData).ToHtmlString();
string expText = ExpressionHelper.GetExpressionText(expression);
string indexText = expText.Substring(expText.IndexOf('[')).Replace("[", string.Empty).Replace("]", string.Empty);
KeyValuePair<TKey, TValue> item = dictionary.SingleOrDefault(p => p.Key.ToString() == indexText);
int index = counter.GetIndex(item.Key);
string key = hiddenKey.Replace("[" + indexText + "]", "[" + index + "].Key").Replace("value=\"" + item.Value + "\"", "value=\"" + item.Key + "\"");
string value = editorValue.Replace("[" + indexText + "]", "[" + index + "].Value");
return new HtmlString(key + value);
}
因为整数索引必须遵循以下规则:
必须以0开头
必须不间断(例如,您不能从3跳到5)
我写了一个计数器类来为我处理整数索引:
public class DictionaryIndexRetrievalCounter<TKey, TValue>
{
private IDictionary<TKey, TValue> _dictionary;
private IList<TKey> _retrievedKeys;
public DictionaryIndexRetrievalCounter(IDictionary<TKey, TValue> dictionary)
{
this._dictionary = dictionary;
this._retrievedKeys = new List<TKey>();
}
public int GetIndex(TKey key)
{
if (!_retrievedKeys.Contains(key))
{
_retrievedKeys.Add(key);
}
return _retrievedKeys.IndexOf(key);
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.