Reputation: 35
I want to create an abstract class and a template editor to generate the html needed.
My problem is: how can I use the attribute DisplayName from the child class ? It always use the abstract class attribute if it exists.
Here are my class:
public abstract class DropDownViewModel
{
public virtual string SelectedId { get; set; }
public IEnumerable<SelectListItem> Items { get; set; }
}
public class UsersDropDown : DropDownViewModel
{
[DisplayName("Users")]
public override string SelectedId { get; set; }
}
Here is my template:
@model DropDownViewModel
@Html.LabelFor(x => x.SelectedId)
@Html.DropDownListFor(
x => x.SelectedId,
new SelectList(Model.Items, "Value", "Text", Model.SelectedId)
)
Any Help would be appreciated.
Upvotes: 2
Views: 468
Reputation: 34992
Your template is defined for the type DropDownViewModel
so MVC will look at attributes in that class. You could define different templates per derived class, but that defeats the purpose of the template (Unless you are planning to generate different html per subclass, in which case just create a template per derived class and you should get the correct attribute used!).
One solution would be setting the DisplayName
attribute in the view model that has the drop down property, like this:
public class YourViewModel
{
[DisplayName("Users")]
public DropDownViewModel UsersDropDown { get; set; }
}
Then move the @Html.LabelFor
to the view rendering the view model, outside the drop down template.
@*Main view rendering the whole view model*@
@model YourViewModel
....
@Html.LabelFor(m=> m.DropDown)
@Html.EditorFor(m=> m.DropDown)
@*DropDownViewModel editor template*@
@model DropDownViewModel
@Html.DropDownListFor(
x => x.SelectedId,
new SelectList(Model.Items, "Value", "Text", Model.SelectedId)
)
With this approach, you don't need multiple subclasses of DropDownViewModel
and the models holding the dropdown are in charge of label names (what if you need to use the Users dropdown in a different context where another label text makes sense?). Please note you can use constants or resources with the DisplayName attribute so you don't need to hardcode the label text on every model that has a users dropdown.
If you need/prefer to keep the label text inside the editor template, then you could just add a string property in the DropDownViewModel class for the label text.
public abstract class DropDownViewModel
{
public string SelectedId { get; set; }
public IEnumerable<SelectListItem> Items { get; set; }
public abstract string LabelText { get; }
}
public class UsersDropDown : DropDownViewModel
{
public override string LabelText { get { return "Users"; } }
}
Then use that property to pass the label text to the @Html.LabelFor
method of the editor template:
@model MvcApplication1.Models.DropDownViewModel
@Html.LabelFor(m => m.SelectedId, Model.LabelText)
@Html.DropDownListFor(
x => x.SelectedId,
new SelectList(Model.Items, "Value", "Text", Model.SelectedId)
)
Note that with this approach you need a derived class per each drop down, but at least the models containing those drop downs could specify the label text if you add a setter to the property.
Hope that helps!
Upvotes: 1