2012-12-19 89 views
7

我有一個如下所示的操作方法。DefaultModelBinder和繼承對象的集合

[AcceptVerbs(HttpVerbs.Post)] 
public ActionResult Create(Form newForm) 
{ 
    ... 
} 

我有一個模型與以下類,我想從ajax JSON數據加載數據。

public class Form 
{ 
    public string title { get; set; } 

    public List<FormElement> Controls { get; set; } 

} 

public class FormElement 
{ 
    public string ControlType { get; set; } 

    public string FieldSize { get; set; } 
} 

public class TextBox : FormElement 
{ 
    public string DefaultValue { get; set; } 
} 

public class Combo : FormElement 
{ 
    public string SelectedValue { get; set; } 
} 

這裏是JSON數據。

{ "title": "FORM1", 
"Controls": 
[ 
{ "ControlType": "TextBox", "FieldSize": "Small" ,"DefaultValue":"test"}, 
{ "ControlType": "Combo", "FieldSize": "Large" , "SelectedValue":"Option1" } 
] 
} 


$.ajax({ 
       url: '@Url.Action("Create", "Form")', 
       type: 'POST', 
       dataType: 'json', 
       data: newForm, 
       contentType: 'application/json; charset=utf-8', 
       success: function (data) { 
        var msg = data.Message; 
       } 
      }); 

DefaultModelBinder正在處理嵌套的對象結構,但它無法解析不同的子類。

什麼是最好的方式來加載List與各自的子類?

+0

你能否更詳細地解釋你想在這裏完成什麼?看起來好像你試圖將整個表單綁定到視圖模型而不是它所攜帶的值。基於後端提供的一些JSON數據,我可以看到動態生成表單的要點,但我很難理解爲什麼您希望僅在用戶填寫表單時再次向後端提供結構本身,而不是值。 –

+0

我沒有動態生成表單。我正在接受代表稍後將在系統中保存的表單結構的json。 – Thurein

回答

1

我查看了mvc DefaultModelBinder實現的代碼。綁定模型時DefaultModelBinder使用GetModelProperties()查找模型的屬性。以下是如何DefaultModelBinder查找屬性:

protected virtual ICustomTypeDescriptor GetTypeDescriptor(ControllerContext controllerContext, ModelBindingContext bindingContext) { 
      return TypeDescriptorHelper.Get(bindingContext.ModelType); 
     } 

TypeDescriptorHelper.Get是使用ModelType這是partent類型(在我的情況FormElement),所以子類(文本框,組合)的屬性不會檢索。

您可以覆蓋該方法並更改行爲以檢索特定的子類型,如下所示。

protected override System.ComponentModel.PropertyDescriptorCollection GetModelProperties(ControllerContext controllerContext, ModelBindingContext bindingContext) 
{ 
    Type realType = bindingContext.Model.GetType(); 
    return new AssociatedMetadataTypeTypeDescriptionProvider(realType).GetTypeDescriptor(realType).GetProperties(); 
} 


protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType) 
     { 
      ValueProviderResult result; 
      result = bindingContext.ValueProvider.GetValue(bindingContext.ModelName + ".ControlType"); 

      if (result == null) 
       return null; 

      if (result.AttemptedValue.Equals("TextBox")) 
       return base.CreateModel(controllerContext, 
         bindingContext, 
         typeof(TextBox)); 
      else if (result.AttemptedValue.Equals("Combo")) 
       return base.CreateModel(controllerContext, 
         bindingContext, 
         typeof(Combo)); 
      return null; 
     }