假设我有两个类一个基类:
public class BaseModel {
}
还有几个孩子:
public class FooModel : BaseModel {
}
public class BarModel : BaseModel {
}
现在我的观点我希望这样的模型:
@model IEnumerable<BaseModel>
在我的行动中,我会按照以下方式传递子课程:
return View(new List<BaseModel>(){ new FooModel(), new BarModel() })
然后我会在一个页面上使用EditFor
编辑这些内容(这很好用)
问题是,当我回发时,我希望能够将这些类型转换为实现类型,但这不起作用。如果我尝试强制转换它,它将为null或抛出异常。
[HttpPost]
public ActionResult BaseModelUpdate(IList<BaseModel > model)
{
// I would like to access items in the list as FooModel and BarModel
}
我怎样才能做到这一点? (将列表中的项目恢复为其子类类型?)
我以为我可以尝试使用TryUpdateModel?
感谢您的帮助。
答案 0 :(得分:2)
您需要指定集合中项目的索引。
这是控制器代码:
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的表达式包含集合中当前项的索引。为什么需要这个是here解释的。简而言之,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());