ViewModel со списком <BaseClass>и шаблонами редактора - PullRequest
37 голосов
/ 26 июня 2011

У меня есть представление, в котором перечислены таблицы, добавляемые в план этажа. Таблицы основаны на TableInputModel для учета RectangleTableInputModel, CircleTableInputModel и т. Д.

ViewModel имеет список TableInputModel, которые являются одним из производных типов.

У меня есть частичное представление для каждого из производных типов, и с учетом List смешанных производных типов среда знает, как их отобразить.

Однако при отправке формы информация о типе теряется. Я пробовал с пользовательским механизмом связывания модели, но поскольку информация о типе теряется при отправке, она не будет работать ...

Кто-нибудь пробовал это раньше?

Ответы [ 2 ]

68 голосов
/ 26 июня 2011

Если у вас есть следующие модели:

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()
    <input type="submit" value="OK" />
}

и соответствующие шаблоны редактора.

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

@model RectangleTableInputModel
<h3>Rectangle</h3>
@Html.Hidden("ModelType", Model.GetType())
@Html.EditorFor(x => x.Foo)

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

@model CircleTableInputModel
<h3>Circle</h3>
@Html.Hidden("ModelType", Model.GetType())
@Html.EditorFor(x => 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(() => model, type);
        return model;
    }
}

, который будет зарегистрирован в Application_Start:

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

и это почти все. Теперь внутри действия Index Post массив моделей будет правильно инициализирован с правильными типами.

2 голосов
/ 24 августа 2011

В mvccontrib было "Подшивка модели производного типа" . Но, к сожалению, в mvccontrib версии 3

такого связующего нет
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...