C# ASP MVC.NET-如何绑定KeyValuePair?

C# ASP MVC.NET-如何绑定KeyValuePair?,c#,asp.net-mvc,data-binding,C#,Asp.net Mvc,Data Binding,有可能约束这种财产吗 public KeyValuePair<string, string> Stuff { get; set; } 公钥值对{get;set;} 我尝试在视图中使用以下代码,但不起作用: <%=Html.Text("Stuff", Model.Stuff.Value)%> <%=Html.Hidden("Model.Stuff.Key", Model.Stuff.Key)%> 可能有用吗?KeyValuePair是一个结构

有可能约束这种财产吗

public KeyValuePair<string, string> Stuff { get; set; }
公钥值对{get;set;}
我尝试在视图中使用以下代码,但不起作用:

<%=Html.Text("Stuff", Model.Stuff.Value)%>    
<%=Html.Hidden("Model.Stuff.Key", Model.Stuff.Key)%>


可能有用吗?

KeyValuePair
是一个结构,而不是一个类,因此每次调用
Stuff
属性都会返回原始
KeyValuePair
的副本。因此,当您绑定到
Model.Stuff.Value
Model.Stuff.Key
时,实际上您正在处理
KeyValuePair
的两个不同实例,它们都不是您模型中的实例。因此,当它们被更新时,它不会更新模型中的Stuff属性。。。量化宽松

顺便说一下,键和值属性是只读的,因此您不能修改它们:您必须替换
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); }
}
private KeyValuePair\u;
公钥密码对
{
获取{return\u stuff;}
设置{u stuff=value;}
}
公共字符串填充密钥
{
获取{return\u stuff.Key;}
set{u stuff=newkeyvaluepair(value,_stuff.value);}
}
公共字符串填充值
{
获取{return\u stuff.Value;}
set{u stuff=newkeypaluepair(_stuff.Key,value);}
}
视图:

<%=Html.Text("Stuff", Model.StuffValue)%>    
<%=Html.Hidden("Model.StuffKey", Model.StuffKey)%>

如果您需要绑定字典,以便每个值都有一个texbox来编辑它,下面是一种使其工作的方法。影响HTML中name属性生成方式的真正重要部分是模型表达式,这是确保模型绑定在回发时发生的部分。此示例仅适用于字典

链接的文章解释了使绑定工作的HTML语法,但它留下了实现这一点的Razor语法相当神秘。此外,本文的不同之处在于,它们允许编辑键和值,并且使用整数索引,即使字典的键是字符串而不是整数。因此,如果您试图绑定一个字典,那么在决定采用哪种方法之前,您确实需要首先评估您是只希望值是可编辑的,还是希望键和值都是可编辑的,因为这些场景是完全不同的

如果您需要绑定到一个复杂的对象,例如Dictionary,那么您应该能够为每个属性创建一个文本框,并在属性中钻取表达式,类似于本文

公共类SomeVM
{
公共字典字段{get;set;}
}
公共类HomeController:控制器
{
[HttpGet]
公共视图结果编辑()
{
SomeVM=新的SomeVM
{
字段=新字典(){
{“Name1”,“Value1”},
{“名称2”,“值2”}
}
};
返回视图(vm);
}
[HttpPost]
public ViewResult Edit(SomeVM)//在vm.Fields中发布值
{
返回视图();
}
}
CSHTML:

仅用于值的编辑器(当然,您可以添加LabelFor以基于键生成标签):

@model mvcapapplication2.Controllers.SomeVM
@使用(Html.BeginForm()){
@Html.ValidationSummary(true)
SomeVM
@foreach(Model.Fields中的var kvpair)
{

@Html.EditorFor(m=>m.Fields[kvpair.Key])//Html:我知道这是一个比较老的问题,但我不喜欢任何建议的解决方案,所以我给出了我的解决方案。 我已经重写了默认模型绑定器来处理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;
    }
公共类CustomModelBinder:DefaultModelBinder
{
公共重写对象BindModel(ControllerContext ControllerContext,ModelBindingContext bindingContext)
{
var model=base.BindModel(controllerContext,bindingContext);
模型=ResolveKeyValuePairs(bindingContext,模型);
收益模型;
}
私有对象ResolveKeyValuePairs(ModelBindingContext bindingContext,对象模型)
{
var type=bindingContext.ModelType;
if(type.IsGenericType)
{
if(type.GetGenericTypeDefinition()==typeof(KeyValuePair))
{                    
var values=bindingContext.ValueProvider作为ValueProviderCollection;
如果(值!=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]);
返回Activator.CreateInstance(bindingContext.ModelType,new[]{keyValue,valueValue});
}
}
}
收益模型;
}

请描述“它不起作用”的含义。确切地说,什么不起作用?您能详细说明一下吗?我正在尝试处理视图中已更新的数据,因此在controller中,我收到了正确的更新模型,但此特定属性没有值。在我的情况下,它是[null,null]。谢谢你的解决方法,它很有效。它看起来不漂亮,但这就足够了。似乎使用类来解决这个问题更干净。令人沮丧的是——更多的代码(如上所述)或其他类。Hrm…谢谢你问这个问题。另外,使用
字典
可以帮助别人。
 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();
        }
    }
@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>
}
    @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
    }
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;
    }