Asp.net-Mvc

帶有 List<BaseClass> 和編輯器模板的 ViewModel

  • June 26, 2011

我有一個視圖,列出了添加到平面圖中的表格。表派生自TableInputModel允許RectangleTableInputModel,CircleTableInputModel

ViewModel 有一個列表,TableInputModel其中所有類型都是派生類型。

我對每個派生類型都有一個部分視圖,並且在給定List混合派生類型的情況下,框架知道如何呈現它們。

但是,在送出表單時,類型資訊會失去。我曾嘗試使用自定義模型綁定器,但由於類型資訊在送出時失去,它不會工作……

有沒有人試過這個?

假設您有以下模型:

public abstract class TableInputModel 
{ 

}

public class RectangleTableInputModel : TableInputModel 
{
   public string Foo { get; set; }
}

public class CircleTableInputModel : TableInputModel 
{
   public string Bar { get; set; }
}

以及以下控制器:

public class HomeController : Controller
{
   public ActionResult Index()
   {
       var model = new TableInputModel[]
       {
           new RectangleTableInputModel(),
           new CircleTableInputModel()
       };
       return View(model);
   }

   [HttpPost]
   public ActionResult Index(TableInputModel[] model)
   {
       return View(model);
   }
}

現在你可以寫視圖了。

主視圖Index.cshtml

@model TableInputModel[]
@using (Html.BeginForm())
{
   @Html.EditorForModel()
   &lt;input type="submit" value="OK" /&gt;
}

和相應的編輯器模板。

~/Views/Home/EditorTemplates/RectangleTableInputModel.cshtml:

@model RectangleTableInputModel
&lt;h3&gt;Rectangle&lt;/h3&gt;
@Html.Hidden("ModelType", Model.GetType())
@Html.EditorFor(x =&gt; x.Foo)

~/Views/Home/EditorTemplates/CircleTableInputModel.cshtml:

@model CircleTableInputModel
&lt;h3&gt;Circle&lt;/h3&gt;
@Html.Hidden("ModelType", Model.GetType())
@Html.EditorFor(x =&gt; x.Bar)

最後缺少的難題是該TableInputModel類型的自定義模型綁定器,它將使用發布的隱藏欄位值來獲取類型並實例化正確的實現:

public class TableInputModelBinder : DefaultModelBinder
{
   protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
   {
       var typeValue = bindingContext.ValueProvider.GetValue(bindingContext.ModelName + ".ModelType");
       var type = Type.GetType(
           (string)typeValue.ConvertTo(typeof(string)), 
           true
       );
       var model = Activator.CreateInstance(type);
       bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() =&gt; model, type);
       return model;
   }
}

將在以下位置註冊Application_Start

ModelBinders.Binders.Add(typeof(TableInputModel), new TableInputModelBinder());

這幾乎就是全部了。現在在 Index Post 操作中,模型數組將使用正確的類型正確初始化。

引用自:https://stackoverflow.com/questions/6484972