是否有可能绑定这种财产?
public KeyValuePair<string, string> Stuff { get; set; }
我尝试在视图中使用以下代码,但它不起作用:
<%=Html.Text("Stuff", Model.Stuff.Value)%>
<%=Html.Hidden("Model.Stuff.Key", Model.Stuff.Key)%>
答案 0 :(得分:8)
KeyValuePair<K,V>
是一个结构,而不是一个类,因此每次调用Stuff
属性都会返回原始KeyValuePair
的副本。因此,当您绑定到Model.Stuff.Value
和Model.Stuff.Key
时,您实际上正在处理KeyValuePair<K,V>
的两个不同实例,其中没有一个是您模型中的实例。因此,当它们更新时,它不会更新模型中的Stuff属性... QED
顺便说一句,Key和Value属性是只读的,因此您无法修改它们:您必须替换KeyValuePair
实例
以下解决方法应该有效:
型号:
private KeyValuePair<string, string> _stuff;
public KeyValuePair<string, string> Stuff
{
get { return _stuff; }
set { _stuff = value; }
}
public string StuffKey
{
get { return _stuff.Key; }
set { _stuff = new KeyValuePair<string, string>(value, _stuff.Value); }
}
public string StuffValue
{
get { return _stuff.Value; }
set { _stuff = new KeyValuePair<string, string>(_stuff.Key, value); }
}
查看:
<%=Html.Text("Stuff", Model.StuffValue)%>
<%=Html.Hidden("Model.StuffKey", Model.StuffKey)%>
答案 1 :(得分:0)
<%=Html.Text("Stuff.Value", Model.Stuff.Value)%>
可能会工作吗?
答案 2 :(得分:0)
如果你需要绑定一个Dictionary,这样每个值都有一个texbox来编辑它,下面是一种让它工作的方法。影响HTML中name属性生成方式的非常重要的部分是模型表达式,它确保在回发时发生模型绑定。此示例仅适用于Dictionary。
链接的文章解释了使绑定工作的HTML语法,但是它留下了Razor语法来实现这一点非常神秘。此外,文章的不同之处在于它们允许编辑键和值,并使用整数索引,即使字典的键是字符串,而不是整数。因此,如果您尝试绑定字典,在确定采用哪种方法之前,首先需要先评估是否只需要值可编辑,或者键和值都是可编辑的,因为这些方案完全不同。 / p>
如果您需要绑定到复杂对象,即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
}
答案 3 :(得分:0)
我知道这是一个较旧的问题,但我不喜欢任何建议的解决方案,所以我给了我的。 我已经重写了默认模型绑定器来处理KeyValuePairs,所以我可以像以前一样使用它们。
public class CustomModelBinder : DefaultModelBinder
{
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var model = base.BindModel(controllerContext, bindingContext);
model = ResolveKeyValuePairs(bindingContext, model);
return model;
}
private object ResolveKeyValuePairs(ModelBindingContext bindingContext, object model)
{
var type = bindingContext.ModelType;
if (type.IsGenericType)
{
if (type.GetGenericTypeDefinition() == typeof (KeyValuePair<,>))
{
var values = bindingContext.ValueProvider as ValueProviderCollection;
if (values != null)
{
var key = values.GetValue(bindingContext.ModelName + ".Key");
var keyValue = Convert.ChangeType(key.AttemptedValue, bindingContext.ModelType.GetGenericArguments()[0]);
var value = values.GetValue(bindingContext.ModelName + ".Value");
var valueValue = Convert.ChangeType(value.AttemptedValue, bindingContext.ModelType.GetGenericArguments()[1]);
return Activator.CreateInstance(bindingContext.ModelType, new[] {keyValue, valueValue});
}
}
}
return model;
}