コレクション内のアイテムのインデックスを指定する必要があります。
コントローラーのコードは次のとおりです。
public class HomeController : Controller
{
//
// GET: /Home/
public ActionResult Index()
{
return
View(new List<BaseModel>() { new BarModel() { BaseProp = "Bar" }, new FooModel() { BaseProp = "Foo" } });
}
[HttpPost]
public ActionResult Index(IList<BaseModel> model)
{
return this.View(model);
}
}
ご覧のとおり、特別なことは何もありません。魔法はビューにあります:
@using MvcApplication1.Models
@model IList<MvcApplication1.Models.BaseModel>
@{
ViewBag.Title = "title";
//Layout = "_Layout";
}
<h2>title</h2>
@using (Html.BeginForm())
{
for (int i = 0; i < Model.Count; i++)
{
@Html.EditorFor(p => p[i])
}
<input type="submit" value="Save" />
}
ご覧のとおり、EditorFor に渡される式には、コレクション内の現在の項目のインデックスが含まれています。これが必要な理由については、こちらで説明しています。簡単に言うと、EditorFor は、name 属性にコレクション内の項目のインデックスが含まれる各プロパティの入力要素を返します。
<input class="text-box single-line" name="[0].BaseProp" type="text" value="Bar" />
アップデート
オブジェクトのタイプを保持しようとしている場合は、特定のモデル タイプを格納する特別なプロパティがモデルに必要であり、IModelBinder
そのプロパティに基づいて特定のモデル インスタンスを作成するカスタム実装が必要です。以下はモデルクラスです。プロパティは非表示のType
入力としてレンダリングされます。
namespace MvcApplication1.Models
{
using System.Web.Mvc;
public class BaseModel
{
public string BaseProp { get; set; }
[HiddenInput(DisplayValue = false)]
public virtual string Type
{
get
{
return _type ?? this.GetType().FullName;
}
set
{
_type = value;
}
}
private string _type;
}
public class FooModel : BaseModel
{
public string FooProp { get; set; }
}
public class BarModel :BaseModel
{
public string BarProp { get; set; }
}
}
これは、カスタム モデル バインダーの実装例です。
public class BaseModelBinder : DefaultModelBinder
{
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
// call to get the BaseModel data so we can access the Type property
var obj = base.BindModel(controllerContext, bindingContext);
var bm = obj as BaseModel;
if(bm != null)
{
//call base.BindModel again but this time with a new
// binding context based on the spefiic model type
obj = base.BindModel(
controllerContext,
new ModelBindingContext(bindingContext)
{
ModelMetadata =
ModelMetadataProviders.Current.GetMetadataForType(null, Type.GetType(bm.Type)),
ModelName = bindingContext.ModelName
});
}
return obj;
}
}
application_start でカスタム バインダーを登録する必要があります。
ModelBinders.Binders.Add(typeof(BaseModel), new BaseModelBinder());