2009-08-19 3 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

"작동하지 않는다"는 것을 의미하십시오. –

+0

정확히 작동하지 않는 것은 무엇입니까? 조금 더 자세히 설명해 주시겠습니까? – Jimmeh

+0

보기에서 업데이트 된 데이터를 처리하려고하므로 컨트롤러에서 올바른 업데이트 된 모델을 받고 있지만이 특정 속성에는 값이 없습니다. 내 경우에는 [null, null]입니다. –

답변

8

KeyValuePair<K,V>은 클래스가 아니므로 Stuff 속성을 호출 할 때마다 원래 KeyValuePair 사본이 반환됩니다. 따라서 Model.Stuff.ValueModel.Stuff.Key에 바인딩하면 KeyValuePair<K,V>이라는 두 개의 서로 다른 인스턴스에서 실제로 작업하고 있습니다. 모델의 인스턴스는 하나도 없습니다. 그들은이 업데이트 될 때, 그것은 그런데 모델의 재료 속성 ... QED

를 업데이트하지 않습니다, 키와 값 속성은 읽기 전용이며, 당신이 그들을 수정할 수 있도록 : 당신이이 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

이것을 위해 클래스를 사용하는 것이 더 깔끔하게 보입니다. 그것은 더 많은 코드 (위와 같음) 또는 다른 클래스를 초조하게 만듭니다. 음 ... 이걸 물어 줘서 고마워. – Cymen

+0

[이] (http://khalidabuhakmeh.com/submitting-a-dictionary-to-an-asp-net-mvc-action),'Dictionary'를 사용하여 게시물을 보내면 누군가를 도울 수 있습니다. – stom

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

작동 할 수 있음?

+0

나는 이것을 시도했지만 그 결과는 같다. –

0

사전을 바인딩해야 각 값에 편집 할 텍사스 상자가 있어야하므로 아래의 방법으로 작동하게 할 수 있습니다. 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

이 질문은 약간 오래된 것으로 알고 있지만 제안 된 해결책이 마음에 들지 않아서 제게 선물을드립니다. KeyValuePair를 처리 할 기본 모델 바인더를 다시 작성하여 이전과 같이 사용할 수 있습니다.

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