Начнём с простой вид модели:Сильно типизированных Общие альтернативы Атрибут
public class MyViewModel
{
public string Value { get; set; }
public IEnumerable<SelectListItem> Values { get; set; }
}
выпадающий список может выглядеть следующим образом:
@Html.DropDownListFor(m => m.Value, Model.Values)
Однако, поскольку выпадающий список требует двух значений она может «т быть использовано как:
public class MyViewModel
{
[UIHint("DropDownList")]
public string Value { get; set; }
public IEnumerable<SelectListItem> Values { get; set; }
}
с видом содержащий:
@Html.EditForModel()
Потому что нет присущего способ выпадающий знать источник, пока вы не derrive от UIHint:
public DropDownListAttribute : UIHintAttribute
{
public DropDownListAttribute (string valuesSource)
: base("DropDownList", "MVC")
{
}
}
Тогда можно было бы использовать его как:
public class MyViewModel
{
[DropDownList("Planets")]
public string PlanetId{ get; set; }
public IEnumerable<SelectListItem> Planets { get; set; }
[DropDownList("Cars")]
public string CarId{ get; set; }
public IEnumerable<SelectListItem> Cars { get; set; }
}
Однако, это не очень строго типизировано, кто-то переименовывает один из magic strings или имена прав, не меняя другого, и он ломается во время выполнения.
Одно теоретическое решение создать общий атрибут:
public DropDownListAttribute<TModel, TValue> : UIHintAttribute
{
public DropDownListAttribute (Expression<Func<TModel, TValue> expression)
: base("DropDownList", "MVC")
{
}
}
и использование будет:
public class MyViewModel
{
[DropDownList<MyViewModel, IEnumerable<SelectListItem>>(m => m.Planets)]
public string PlanetId{ get; set; }
public IEnumerable<SelectListItem> Planets { get; set; }
}
But (currently) Generic Attributes aren't allowed:/
Другой вариант заключается в инкапсуляции два в один класс, который ModelBinder может воссоздать на обратной стороне:
public class DropDownListTemplate
{
public string SelectedValue { get; set; }
public IEnumerable<SelectListItem> Values { get; set; }
}
public class MyViewModel
{
public DropDownListTemplate Planet { get; set; }
}
Это создает простоту в шаблонах ViewModel, Binding и EditFor/DisplayFor, но из моих ограниченных знаний об AutoMapper это добавляет сложности, когда AutoMapper Mapping to Properties of Class Properties. Насколько я знаю, я не могу просто:
public class MyPlanets
{
public string SelectedPlanet { get; set; }
}
Mapper.CreateMap<MyPlanets, MyViewModel>();
Mapper.CreateMap<MyViewModel, MyPlanets>();
Есть ли более простой способ с automapper отобразить эти значения автоматически волшебно или есть способ создания сильно типизированных необщего атрибут?
Даже если вы не использовали генерики, я не верю, что C# позволит вам использовать лямбда-выражения, украшая элементы с пользовательскими атрибутами. Это в значительной степени ограничено литералами и выражениями typeof(). – StriplingWarrior
@ StriplingWarrior oh хорошая точка! Нет 'Expression',' Func' и т. Д. ... yeesh. Возможно, я могу [зависимость вводить выпадающие значения непосредственно в атрибут] (http://stackoverflow.com/questions/4695902/asp-net-mvc-3-action-filters-and-autofac-dependency-injection). .. :) –
@ErikPhilips вам придется переопределить шаг активатора атрибутов, не так ли? Поскольку ваши конструкторы будут хотеть ценности, когда вы их украшаете. Возможно, вложение свойств внутри атрибута ... сложно. Вам все равно придется переопределить фазу построения атрибута. –