2009-08-19 35 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; 
    }