2009-08-19 36 views
11

是否可以绑定这样的属性?ASP MVC.NET - 如何绑定KeyValuePair?

public KeyValuePair<string, string> Stuff { get; set; } 

我试过在视图中使用下面的代码,但它不工作:

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

请说明“它不起作用”的含义。 – 2009-08-19 15:21:48

+0

究竟哪些不起作用?你能否详细说明一下? – Jimmeh 2009-08-19 15:23:05

+0

我想处理已在视图上更新的数据,所以在控制器中,我正在接收正确的更新模型,但此特定属性没有值。在我的情况下,它是[null,null]。 – 2009-08-19 15:31:12

回答

8

KeyValuePair<K,V>是一个结构,而不是一个类,所以每个呼叫您的Stuff属性返回原始KeyValuePair的副本。所以,当你绑定到Model.Stuff.ValueModel.Stuff.Key时,实际上是工作的KeyValuePair<K,V>两个不同的实例,其中没有一个是从模型中的一个。因此,当他们被更新,它不会更新模型中的东西财产...... 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

谢谢你的解决方法,它的工作原理。它看起来不漂亮,但对于这种情况就足够了。 – 2009-08-19 15:48:35

+0

看起来像使用这个类更清洁。令人沮丧的是 - 更多的代码(如上)或另一个类。 Hrm ...感谢您提出这个问题。 – Cymen 2011-06-02 17:07:55

+0

另外[this](http://khalidabuhakmeh.com/submitting-a-dictionary-to-an-asp-net-mvc-action),使用'Dictionary'可以帮助某人。 – stom 2017-01-25 10:23:42

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

可能会奏效?

+0

我试过这个,但结果是一样的。 – 2009-08-19 15:28:12

0

如果您需要绑定一个字典,使得每个值有texbox进行编辑,下面是使它工作的一种方式。影响HTML中名称属性的真正重要部分是模型表达式,它确保模型绑定在回发时发生。本示例仅适用于Dictionary。

链接的文章解释了HTML语法,使结合的工作,但它留下的剃刀语法来做到这一点相当神秘。另外,文章的区别在于它们允许编辑键和值,并且即使字典的键是字符串而不是整数,也使用整数索引。因此,如果您尝试绑定字典,则在决定采用哪种方法之前,您确实需要首先评估是否只需要值为可编辑值,或者同时使用键和值,因为这些场景完全不同。

如果你需要绑定到一个复杂的对象,即字典,那么你就应该能够有与表达钻入属性,类似的文章每个属性文本框。

http://www.hanselman.com/blog/ASPNETWireFormatForModelBindingToArraysListsCollectionsDictionaries.aspx

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 
    } 
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; 
    }