Иногда я буду заканчивать с очень длинными идентификаторами, но я называю их последовательно для соответствия их точной цели.
, Например...
<div id="page">
<div id="primary-content"></div>
<div id="secondary-content"></div>
<div id="search-form-and-primary-nav-wrapper">
<form id="search-form"></form>
<ul id="primary-nav">
<li id="primary-nav-about-us"></li>
</ul>
</div>
<a id="logo"><img /></a>
</div><!-- /#page -->
, Как Вы видите, селекторы иногда довольно длинны. Но настолько легче, по моему скромному мнению, чем работа с чем-то как YUI grids.css, где Вы заканчиваете с идентификаторами как #doc, #bd, #yui-main, и т.д.
Здесь обсуждалось отсутствие проверки фактического типа интерфейса: http://forums.asp.net/t/1348233.aspx
Тем не менее, я нашел хакерский способ обойти проблему. Так как у меня уже была настраиваемая привязка модели для этого типа, я смог добавить в нее код, чтобы выполнить привязку за меня. Вот как теперь выглядит моя связыватель модели:
public class AccountViewModelModelBinder : DefaultModelBinder
{
private readonly IProfileViewModel profileViewModel;
private bool profileBound = false;
public AccountViewModelModelBinder(IProfileViewModel profileViewModel)
{
this.profileViewModel = profileViewModel;
}
protected override void OnModelUpdated(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
// Bind the profile
if (profileBound)
return;
profileBound = true;
bindingContext.ModelType = profileViewModel.GetType();
bindingContext.Model = profileViewModel;
bindingContext.ModelName = "Profile";
BindModel(controllerContext, bindingContext);
}
protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, System.Type modelType)
{
var model = new AccountViewModel();
model.Profile = profileViewModel;
return model;
}
}
В основном, когда связыватель модели "завершил" привязку основного AccountViewModel, я затем изменяю контекст привязки (как предлагает Эйстон) и снова вызываю BindModel. Затем это связывает мой профиль. Обратите внимание, что я вызвал GetType для profileViewModel (который предоставляется контейнером IOC в конструкторе). Также обратите внимание, что я включил флаг, чтобы указать, была ли уже привязана модель профиля. Иначе получился бы бесконечный цикл вызова OnModelUpdated.
Я не говорю, что это красиво, но это работает достаточно хорошо для моих нужд. Я все еще хотел бы услышать другие предложения.
Мне нужно было бы проверить код ASP.NET MVC (DefaultModelBinder), но я предполагаю, что он отражает тип IProfile, а не экземпляр StandardProfile.
Так что это выглядит для любых членов IProfile он может попытаться привязать, но это пустой интерфейс, поэтому он считает себя выполненным.
Вы можете попробовать что-то вроде обновления BindingContext и изменения ModelType на StandardProfile, а затем вызвать
bindingContext.ModelType = typeof(StandardProfile);
IProfile profile = base.BindModel(controllerContext, bindingContext);
В любом случае, имея пустой Интерфейс странный ~
Изменить: просто хочу добавить, что приведенный выше код - это просто псевдокод, вам нужно будет проверить DefaultModelBinder, чтобы увидеть, что именно вы хотите написать.
Изменить # 2:
Можете ли вы сделать:
public class ProfileModelBinder : DefaultModelBinder
{
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) {
{
bindingContext.ModelType = typeof(StandardProfile);
return base.BindModel(controllerContext, bindingContext);
}
}
Нет необходимости создавать привязку модели для AccountView, она работает нормально.
Редактировать # 3
Протестировано, указанная привязка работает, просто нужно добавить:
ModelBinders.Binders[typeof(IProfile)] = new ProfileModelBinder();
Ваше действие выглядит следующим образом:
public ActionResult AddAccount(AccountViewModel viewModel) {
// viewModel is fully populated, including profile, don't call UpdateModel
}
Вы можете использовать IOC при установке связывателя модели (например, внедрить конструктор типа).