How can I make a default editor template for enums? By which I mean: can I do something like this:
<%@ Control Language=\"C#\" Inherits=\"System.Web.Mvc.V
Yes
Almost sure this works out of the box.
Try naming your template the same name as your enum.
I made the dropdownlistfor method a bit easier and now you can give a selectedValue with it:
public static MvcHtmlString DropDownListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, Type enumType)
{
return DropDownListFor(htmlHelper, expression, enumType, null);
}
public static MvcHtmlString DropDownListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, Type enumType, object selectedValue)
{
Dictionary<string, string> enumItems = enumType.GetDisplayNames(htmlHelper.ViewContext.HttpContext);
return htmlHelper.DropDownListFor(expression, new SelectList(enumItems, "Key", "Value", selectedValue));
}
Use it like this in your View:
@Html.DropDownListFor(m => m.Gender, typeof(Gender), Model.Gender)
Model is my MVC Model and its property Gender contains the selectedValue for the DropDownListFor.
Late to answer but I hope this helps others. Ideally you want all enums to use your Enum template by convention, not by specifying a UIHint each time, and you can accomplish that by creating a custom model metadata provider like this:
using System;
using System.Collections.Generic;
using System.Web.Mvc;
public class CustomMetadataProvider : DataAnnotationsModelMetadataProvider
{
protected override ModelMetadata CreateMetadata(IEnumerable<Attribute> attributes, Type containerType, Func<object> modelAccessor, Type modelType, string propertyName) {
var mm = base.CreateMetadata(attributes, containerType, modelAccessor, modelType, propertyName);
if (modelType.IsEnum && mm.TemplateHint == null) {
mm.TemplateHint = "Enum";
}
return mm;
}
}
Then simply register it in the Application_Start method of Global.asax.cs:
ModelMetadataProviders.Current = new CustomMetadataProvider();
Now all your enum properties will use your Enum template by default.
I don't think there is a default way to define an editor for all enum types because you could want different behavior depending on the situation. For example, maybe you have a [Flags] enum and want multi select, or you want a dropdownlist, or you want radio buttons.
Plus, generally you are going to want some sort of meaningful display string beyond what you can accomplish in the variable naming limitations.
Certainly assigning to a property of type enum works out of the box but how you get that value is going to be up to you.
Nour Sabony, I modified your version to also support localization with resources. Therefore I changed the DescriptionAttribute to the DisplayAttribute of the DataAnnotations namespace
public static MvcHtmlString DropDownListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, Type enumType)
{
List<SelectListItem> list = new List<SelectListItem>();
Dictionary<string, string> enumItems = enumType.GetDisplayNames(htmlHelper.ViewContext.HttpContext);
foreach (KeyValuePair<string, string> pair in enumItems)
list.Add(new SelectListItem() { Value = pair.Key, Text = pair.Value });
return htmlHelper.DropDownListFor(expression, list);
}
/// <summary>
/// return the items of enum paired with its DisplayName.
/// </summary>
/// <param name="enumeration">enumeration type to be processed.</param>
/// <returns></returns>
public static Dictionary<string, string> GetDisplayNames(this Type enumeration, HttpContextBase httpContext)
{
if (!enumeration.IsEnum)
{
throw new ArgumentException("passed type must be of Enum type", "enumerationValue");
}
Dictionary<string, string> displayNames = new Dictionary<string, string>();
var members = enumeration.GetMembers().Where(m => m.MemberType == MemberTypes.Field);
foreach (MemberInfo member in members)
{
var attrs = member.GetCustomAttributes(typeof(DisplayAttribute), false);
if (attrs.Count() != 0)
if (((DisplayAttribute)attrs[0]).ResourceType != null)
{
displayNames.Add(member.Name, ((DisplayAttribute)attrs[0]).GetName(););
}
else
{
displayNames.Add(member.Name, ((DisplayAttribute)attrs[0]).Name);
}
}
return displayNames;
}
The definition of an enum has to look like this now:
public enum Gender
{
[Display(Name = "Male", ResourceType = typeof(mynamespace.App_LocalResources.Shared))]
Male = 1,
[Display(Name = "Female", ResourceType = typeof(mynamespace.App_LocalResources.Shared))]
Female = 2,
}
it can be used in a View in the same way, e.g. (Razor):
@Html.DropDownListFor(model => model.Gender, typeof(Gender))
Hope this helps someone!
Thank you all for your contributions
Yngvebn, i tried your solution (in your last comment) before, but the only thing i didn't do is the <dynamic>
, i used instead <Enum>
in generic type.
at last the solution is :
create a template named Enum.acsx and put it under the Views\Shared\EditorTemplates
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<dynamic>" %>
<%@ Import Namespace="System.Web.Mvc.Html" %>
<%@ Import Namespace="the extension methods namespace" %>
<% Enum model = (Enum)Model; %>
<%=Html.DropDownList(model.GetType().Name,model.GetType())%>
and in your Entity:
public class Person
{
[UIHint("Enum")]
public GenderEnum Gender{get;set;}
}
public Enum GenderEnum
{
[Description("Male Person")]
Male,
[Description("Female Person")]
Female
}
and again there is Extention Methods:
public static class HtmlHelperExtension
{
public static MvcHtmlString DropDownListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, Type enumType)
{
List<SelectListItem> list = new List<SelectListItem>();
Dictionary<string, string> enumItems = enumType.GetDescription();
foreach (KeyValuePair<string, string> pair in enumItems)
list.Add(new SelectListItem() { Value = pair.Key, Text = pair.Value });
return htmlHelper.DropDownListFor(expression, list);
}
/// <summary>
/// return the items of enum paired with its descrtioption.
/// </summary>
/// <param name="enumeration">enumeration type to be processed.</param>
/// <returns></returns>
public static Dictionary<string, string> GetDescription(this Type enumeration)
{
if (!enumeration.IsEnum)
{
throw new ArgumentException("passed type must be of Enum type", "enumerationValue");
}
Dictionary<string, string> descriptions = new Dictionary<string, string>();
var members = enumeration.GetMembers().Where(m => m.MemberType == MemberTypes.Field);
foreach (MemberInfo member in members)
{
var attrs = member.GetCustomAttributes(typeof(DescriptionAttribute), false);
if (attrs.Count() != 0)
descriptions.Add(member.Name, ((DescriptionAttribute)attrs[0]).Description);
}
return descriptions;
}
}