ListFor enum flags MVC.Net - c#

My model contains an enum with a flags attribute
[Flags()]
public enum InvestmentAmount
{
[Description("£500 - £5,000")]
ZeroToFiveThousand,
[Description("£5,000 - £10,000")]
FiveThousandToTenThousand,
//Deleted remaining entries for size
}
I want to be able to display this in my view as a multiselectable List box.
Obviously the current helper for Listfor() doesn't support enums.
I've tried rolling my own but just receive
The parameter 'expression' must evaluate to an IEnumerable when
multiple selection is allowed.
when it executes.
public static MvcHtmlString EnumListFor<TModel, TEnum>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TEnum>> expression, object htmlAttributes)
{
ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
Type enumType = GetNonNullableModelType(metadata);
IEnumerable<TEnum> values = Enum.GetValues(enumType).Cast<TEnum>();
IEnumerable<SelectListItem> items = from value in values
select new SelectListItem
{
Text = GetEnumDescription(value),
Value = value.ToString(),
Selected = value.Equals(metadata.Model)
};
// If the enum is nullable, add an 'empty' item to the collection
if (metadata.IsNullableValueType)
items = SingleEmptyItem.Concat(items);
RouteValueDictionary htmlattr = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);
//htmlattr.Add("multiple", "multiple");
if (expression.GetDescription() != null)
{
htmlattr.Add("data-content", expression.GetDescription());
htmlattr.Add("data-original-title", expression.GetTitle());
htmlattr["class"] = "guidance " + htmlattr["class"];
}
var fieldName = htmlHelper.NameFor(expression).ToString();
return htmlHelper.ListBox(fieldName, items, htmlattr); //Exception thrown here
}

Check out my blog post on a helper method I created to do just this:
http://jnye.co/Posts/4/creating-a-dropdown-list-from-an-enum-in-mvc-and-c%23
This enables you to do something like this:
//If you don't have an enum value use the type
var enumList = EnumHelper.SelectListFor<MyEnum>();
//If you do have an enum value use the value (the value will be marked as selected)
var enumList = EnumHelper.SelectListFor(myEnumValue);
...which you can then use to build your multi list.
The helper class is as follows:
public static class EnumHelper
{
//Creates a SelectList for a nullable enum value
public static SelectList SelectListFor<T>(T? selected)
where T : struct
{
return selected == null ? SelectListFor<T>()
: SelectListFor(selected.Value);
}
//Creates a SelectList for an enum type
public static SelectList SelectListFor<T>() where T : struct
{
Type t = typeof (T);
if (t.IsEnum)
{
var values = Enum.GetValues(typeof(T)).Cast<enum>()
.Select(e => new { Id = Convert.ToInt32(e), Name = e.GetDescription() });
return new SelectList(values, "Id", "Name");
}
return null;
}
//Creates a SelectList for an enum value
public static SelectList SelectListFor<T>(T selected) where T : struct
{
Type t = typeof(T);
if (t.IsEnum)
{
var values = Enum.GetValues(t).Cast<Enum>()
.Select(e => new { Id = Convert.ToInt32(e), Name = e.GetDescription() });
return new SelectList(values, "Id", "Name", Convert.ToInt32(selected));
}
return null;
}
// Get the value of the description attribute if the
// enum has one, otherwise use the value.
public static string GetDescription<TEnum>(this TEnum value)
{
FieldInfo fi = value.GetType().GetField(value.ToString());
if (fi != null)
{
DescriptionAttribute[] attributes =
(DescriptionAttribute[])fi.GetCustomAttributes(
typeof(DescriptionAttribute),
false);
if (attributes.Length > 0)
{
return attributes[0].Description;
}
}
return value.ToString();
}
}

The error appears to have been occurring because I was binding to just an "InvestmentAmount" where as it appears that ListFor checks if the model is a list.
I've had to change my model to a List and build in binding logic (Through AutoMapper) to convert from the flagged Enum to a List and back.
A nicer solution would be to create a generic HTML ListFor helper to do it. Which is the way I'll tackle it if I need it any more than once.

Related

Access Enum custom attributes whilst looping over values

I have added a custom attribute to some enum values (to give them a screen friendly string value). I am trying to build a list of SelectListItems for use on an MVC page, but I am running into trouble accessing the custom attribute.
My enum looks like this.
public enum MyEnum
{
[StringValue("None")] None = 0,
[StringValue("First Value")] FirstValue = 1,
[StringValue("Second Value")] SecondValue = 2
}
The attribute looks like this.
public class StringValueAttribute : Attribute
{
public StringValueAttribute(string value)
{
this.StringValue = value;
}
public string StringValue { get; protected set; }
}
I created a helper class so that I can easily access the StringValue attribute from an instance of the Enum.
public static string GetStringValue(this Enum value)
{
Type type = value.GetType();
FieldInfo fieldInfo = type.GetField(value.ToString());
StringValueAttribute[] attribs = fieldInfo.GetCustomAttributes(typeof(StringValueAttribute), false) as StringValueAttribute[];
return attribs != null && attribs.Length > 0 ? attribs[0].StringValue : null;
}
I could call it like this.
MyEnum test = MyEnum.FirstValue;
string stringValue = test.GetStringValue();
Finally, onto the code I am stuck with. I can loop over the Enum Values easily, but the values are not instances of MyEnum so I cannot call my helper function. And when I try to access the FieldInfo it always returns null. Here is what I have so far.
public static List<SelectListItem> GetFlagsSelectList<T>(int? selectedValue)
{
List<SelectListItem> items = new List<SelectListItem>();
foreach (int value in Enum.GetValues(typeof(T)))
{
items.Add(new SelectListItem
{
Text = Enum.GetName(typeof(T), value),
Value = value.ToString(),
Selected = selectedValue.HasValue && selectedValue.Value == value
});
}
return items;
}
Is it possible to access the custom attribute within the foreach loop?
EDIT:
I think I asked this unclearly. I would like to access the custom attribute inside the foreach loop. Calling Enum.GetName(typeof(T), value) simply returns the name of the property (e.g. FirstValue) which I do NOT want.
I would like to do something like:
foreach (int value in Enum.GetValues(typeof(T)))
{
string name = Enum.ToObject(typeof (T), value).GetStringValue();
}
But T could be any type so I can't call my GetStringValue() method there.
I have tried doing this:
foreach (int value in Enum.GetValues(typeof(T)))
{
FieldInfo fieldInfo = typeof(T).GetField(value.ToString());
StringValueAttribute[] attribs = fieldInfo.GetCustomAttributes(typeof(StringValueAttribute), false) as StringValueAttribute[];
string name = attribs != null && attribs.Length > 0 ? attribs[0].StringValue : Enum.GetName(typeof(T), value),;
items.Add(new SelectListItem
{
Text = name,
Value = value.ToString(),
Selected = selectedValue.HasValue && selectedValue.Value == value
});
}
But I always get an exception because the FieldInfo object always returns null.
Try
static string GetStringValue2(Enum value) {
....
}
public static List<SelectListItem> GetFlagsSelectList<T>(int? selectedValue) where T : struct {
var items = new List<SelectListItem>();
foreach (T value in Enum.GetValues(typeof(T))) {
var stringValue = GetStringValue2((Enum)(object)value);
items.Add(new SelectListItem {
Text = Enum.GetName(typeof(T), value),
Value = Convert.ToInt32(value).ToString(),
Selected = selectedValue.HasValue && selectedValue.Value == Convert.ToInt32(value)
});
}
return items;
}
I wrote a blog post about this a while back (for the XmlEnumAttribute, but the same applies here).
public static string ConvertToString(Enum e)
{
// Get the Type of the enum
Type t = e.GetType();
// Get the FieldInfo for the member field with the enums name
FieldInfo info = t.GetField(e.ToString("G"));
// Check to see if the XmlEnumAttribute is defined on this field
if (!info.IsDefined(typeof(XmlEnumAttribute), false))
{
// If no XmlEnumAttribute then return the string version of the enum.
return e.ToString("G");
}
// Get the XmlEnumAttribute
object[] o = info.GetCustomAttributes(typeof(XmlEnumAttribute), false);
XmlEnumAttribute att = (XmlEnumAttribute)o[0];
return att.Name;
}
Hope that helps.

Generic Enum to SelectList extension method

I need to create a SelectList from any Enum in my project.
I have the code below which I create a select list from a specific enum, but I'd like to make an extension method for ANY enum. This example retrieves the value of the DescriptionAttribute on each Enum value
var list = new SelectList(
Enum.GetValues(typeof(eChargeType))
.Cast<eChargeType>()
.Select(n => new
{
id = (int)n,
label = n.ToString()
}), "id", "label", charge.type_id);
Referencing this post, how do I proceed?
public static void ToSelectList(this Enum e)
{
// code here
}
What I think you are struggling with, is the retrieval of the description. I'm sure once you have those that you can define your final method which gives your exact result.
First, if you define an extension method, it works on a value of the enum, not on the enum type itself. And I think, for easy of usage, you would like to call the method on the type (like a static method). Unfortunately, you cannot define those.
What you can do is the following. First define a method which retrieves the description of the enum value, if it has one:
public static string GetDescription(this Enum value) {
string description = value.ToString();
FieldInfo fieldInfo = value.GetType().GetField(description);
DescriptionAttribute[] attributes = (DescriptionAttribute[])fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
if (attributes != null && attributes.Length > 0) {
description = attributes[0].Description;
}
return description;
}
Next, define a method which takes all values of an enum, and use the previous method to look up the value which we want to show, and return that list. The generic argument can be inferred.
public static List<KeyValuePair<TEnum, string>> ToEnumDescriptionsList<TEnum>(this TEnum value) {
return Enum
.GetValues(typeof(TEnum))
.Cast<TEnum>()
.Select(x => new KeyValuePair<TEnum, string>(x, ((Enum)((object)x)).GetDescription()))
.ToList();
}
And finally, for ease of usage, a method to call it directly without value. But then the generic argument is not optional.
public static List<KeyValuePair<TEnum, string>> ToEnumDescriptionsList<TEnum>() {
return ToEnumDescriptionsList<TEnum>(default(TEnum));
}
Now we can use it like this:
enum TestEnum {
[Description("My first value")]
Value1,
Value2,
[Description("Last one")]
Value99
}
var items = default(TestEnum).ToEnumDescriptionsList();
// or: TestEnum.Value1.ToEnumDescriptionsList();
// Alternative: EnumExtensions.ToEnumDescriptionsList<TestEnum>()
foreach (var item in items) {
Console.WriteLine("{0} - {1}", item.Key, item.Value);
}
Console.ReadLine();
Which outputs:
Value1 - My first value
Value2 - Value2
Value99 - Last one
Late to the party, but since there is no accepted answer and it might help others:
As #Maarten mentioned, an extension method works on the value of an enum, not the enum type itelf, so as with Maarteen's soultion you can create a dummy or default value to call the extension method on, however, you may find, as I did, that it is simpler to just use a static helper method like so:
public static class EnumHelper
{
public static SelectList GetSelectList<T>(string selectedValue, bool useNumeric = false)
{
Type enumType = GetBaseType(typeof(T));
if (enumType.IsEnum)
{
var list = new List<SelectListItem>();
// Add empty option
list.Add(new SelectListItem { Value = string.Empty, Text = string.Empty });
foreach (Enum e in Enum.GetValues(enumType))
{
list.Add(new SelectListItem { Value = useNumeric ? Convert.ToInt32(e).ToString() : e.ToString(), Text = e.Description() });
}
return new SelectList(list, "Value", "Text", selectedValue);
}
return null;
}
private static bool IsTypeNullable(Type type)
{
return (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>));
}
private static Type GetBaseType(Type type)
{
return IsTypeNullable(type) ? type.GetGenericArguments()[0] : type;
}
You would create the select list like this:
viewModel.ProvinceSelect = EnumHelper.GetSelectList<Province>(model.Province);
or using the optional numeric values instead of strings:
viewModel.MonthSelect = EnumHelper.GetSelectList<Month>(model.Month,true);
The basic idea for this I got from here, though I changed it to suit my needs. One thing I added was the ability to optionally use ints for the value. I also added an enum extension to get the description attribute which is based on this blog post:
public static class EnumExtensions
{
public static string Description(this Enum en)
{
Type type = en.GetType();
MemberInfo[] memInfo = type.GetMember(en.ToString());
if (memInfo != null && memInfo.Length > 0)
{
object[] attrs = memInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false);
if (attrs != null && attrs.Length > 0)
{
return ((DescriptionAttribute)attrs[0]).Description;
}
}
return en.ToString();
}
}
Since enum can't have extensions pinned to the entire collection a convenient way to extend the Enum base class is with a static typed class. This will allow concise code such as:
Enum<MyCustomEnumType>.GetSelectItems();
Which can be achieved with the following code:
public static class Enum<T>
{
public static SelectListItem[] GetSelectItems()
{
Type type = typeof(T);
return
Enum.GetValues(type)
.Cast<object>()
.Select(v => new SelectListItem() { Value = v.ToString(), Text = Enum.GetName(type, v) })
.ToArray();
}
}
Since enum do not have a shared interface Type misuse is possible, but the class name Enum should dispell any confusion.
Here is a corrected [type casted value to int] and simplified [uses tostring override instead of getname] version of Nathaniels answer that returns a List instead of an array:
public static class Enum<T>
{
//usage: var lst = Enum<myenum>.GetSelectList();
public static List<SelectListItem> GetSelectList()
{
return Enum.GetValues( typeof(T) )
.Cast<object>()
.Select(i => new SelectListItem()
{ Value = ((int)i).ToString()
,Text = i.ToString() })
.ToList();
}
}

enum values in drop down list using ViewData and th viewcode to list it?

How can I create a dropdown list using an enum value in ASP.NET MVC 4?
I have a Language enumeration:
public enum Language
{
English = 0,
spanish = 2,
Arabi = 3
}
And my property is:
public Language Language { get; set; }
And my Controller action looks like this:
[HttpPost]
public ActionResult Edit(tList tableSheet)
{
return RedirectToAction("Index");
}
How will I call in my view through a dropdown list using ViewData[]?
This will return
Enum.GetNames(typeOf(Language ))
English
spanish
Arabi
And this
Enum.GetValues(typeOf(Language ))
1,2,3
You can languages list to view:
ViewBeg.Languages = Enum.GetNames(typeOf(Language)).ToList();
I know i'm late to the party but... check out a helper class I created to do just this...
http://jnye.co/Posts/4/creating-a-dropdown-list-from-an-enum-in-mvc-and-c%23
This helpe can be used as follows:
In the controller:
//If you don't have an enum value use the type
ViewBag.DropDownList = EnumHelper.SelectListFor<Language>();
//If you do have an enum value use the value (the value will be marked as selected)
ViewBag.DropDownList = EnumHelper.SelectListFor(myEnumValue);
In the view
#Html.DropDownList("DropDownList")
Helper:
public static class EnumHelper
{
//Creates a SelectList for a nullable enum value
public static SelectList SelectListFor<T>(T? selected)
where T : struct
{
return selected == null ? SelectListFor<T>()
: SelectListFor(selected.Value);
}
//Creates a SelectList for an enum type
public static SelectList SelectListFor<T>() where T : struct
{
Type t = typeof (T);
if (t.IsEnum)
{
var values = Enum.GetValues(typeof(T)).Cast<enum>()
.Select(e => new { Id = Convert.ToInt32(e), Name = e.GetDescription() });
return new SelectList(values, "Id", "Name");
}
return null;
}
//Creates a SelectList for an enum value
public static SelectList SelectListFor<T>(T selected) where T : struct
{
Type t = typeof(T);
if (t.IsEnum)
{
var values = Enum.GetValues(t).Cast<Enum>()
.Select(e => new { Id = Convert.ToInt32(e), Name = e.GetDescription() });
return new SelectList(values, "Id", "Name", Convert.ToInt32(selected));
}
return null;
}
// Get the value of the description attribute if the
// enum has one, otherwise use the value.
public static string GetDescription<TEnum>(this TEnum value)
{
FieldInfo fi = value.GetType().GetField(value.ToString());
if (fi != null)
{
DescriptionAttribute[] attributes =
(DescriptionAttribute[])fi.GetCustomAttributes(
typeof(DescriptionAttribute),
false);
if (attributes.Length > 0)
{
return attributes[0].Description;
}
}
return value.ToString();
}
}

Display enum in dropdown with Html.DropdownListFor

in a model file I have
public enum Title
{
Ms,
Mrs,
Mr
}
I would like to display on the register form's downdown box these selectable values.
But I don't know how. It doesn't necessarily require me to use an enum, provided those titles could be in use with dropdownlistfor, please you can suggest me any methods. Thank you.
you can bind it like this
ddl.DataSource = Enum.GetNames(typeof(Title));
ddl.DataBind();
if you want to get the selected value as well do the following
Title enumTitle = (Title)Enum.Parse(ddl.SelectedValue);
There are a couple of methods to this.
One is to create a method that returns a select list.
private static SelectList ToSelectList(Type enumType, string selectedItem)
{
var items = new List<SelectListItem>();
foreach (var item in Enum.GetValues(enumType))
{
var title = ((Enum)item).GetDescription();
var listItem = new SelectListItem
{
Value = ((int)item).ToString(),
Text = title,
Selected = selectedItem == item.ToString()
};
items.Add(listItem);
}
return new SelectList(items, "Value", "Text");
}
The second method is to create helper method
public static MvcHtmlString EnumDropDownListFor<TModel, TEnum>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TEnum>> expression, string optionLabel, object htmlAttributes)
{
ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
Type enumType = GetNonNullableModelType(metadata);
IEnumerable<TEnum> values = Enum.GetValues(enumType).Cast<TEnum>();
IEnumerable<SelectListItem> items = from value in values
select new SelectListItem
{
Text = GetEnumDescription(value),
Value = value.ToString(),
Selected = value.Equals(metadata.Model)
};
// If the enum is nullable, add an 'empty' item to the collection
if (metadata.IsNullableValueType)
{
items = SingleEmptyItem.Concat(items);
}
return htmlHelper.DropDownListFor(expression, items, optionLabel, htmlAttributes);
}
public static string GetEnumDescription<TEnum>(TEnum value)
{
FieldInfo fi = value.GetType().GetField(value.ToString());
DescriptionAttribute[] attributes = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false);
if ((attributes != null) && (attributes.Length > 0))
{
return attributes[0].Description;
}
return value.ToString();
}
I use a combination of things. First off, here's an extension method for Enums to get all enum items in a collection from an enum type:
public static class EnumUtil
{
public static IEnumerable<T> GetEnumValuesFor<T>()
{
return Enum.GetValues(typeof(T)).Cast<T>();
}
}
Then, I have some code to turn a List into a List. You can indicate which of the values you are passing in are already Selected (just 1 for a Dropdown list, but you can use this to power a CheckBoxList as well), as well has indicating ones to exclude too, if necessary.
public static List<SelectListItem> GetEnumsByType<T>(bool useFriendlyName = false, List<T> exclude = null,
List<T> eachSelected = null, bool useIntValue = true) where T : struct, IConvertible
{
var enumList = from enumItem in EnumUtil.GetEnumValuesFor<T>()
where (exclude == null || !exclude.Contains(enumItem))
select enumItem;
var list = new List<SelectListItem>();
foreach (var item in enumList)
{
var selItem = new SelectListItem();
selItem.Text = (useFriendlyName) ? item.ToFriendlyString() : item.ToString();
selItem.Value = (useIntValue) ? item.To<int>().ToString() : item.ToString();
if (eachSelected != null && eachSelected.Contains(item))
selItem.Selected = true;
list.Add(selItem);
}
return list;
}
public static List<SelectListItem> GetEnumsByType<T>(T selected, bool useFriendlyName = false, List<T> exclude = null,
bool useIntValue = true) where T : struct, IConvertible
{
return GetEnumsByType<T>(
useFriendlyName: useFriendlyName,
exclude: exclude,
eachSelected: new List<T> { selected },
useIntValue: useIntValue
);
}
And then in my View Model, when I need to fill a DropdownList, I can just grab the List from that helper method like so:
public class AddressModel
{
public enum OverrideCode
{
N,
Y,
}
public List<SelectListItem> OverrideCodeChoices { get {
return SelectListGenerator.GetEnumsByType<OverrideCode>();
} }
}
A little late but you can just use the Html helpers:
#Html.GetEnumSelectList<Title>()

MVC3 EnumDropdownList selected value

There are some helpful extension methods for using displaying enums in dropdown lists. For example here and here.
But there is one problem that I encounter, which is that these helpers do not work if the enum is decorated with the Description attribute. The first example works perfectly with the Description attribute, but it doesn't set the selected value. The second example sets the selected value, but it doesn't use the description attribute. So I need to combine both methods into a working helper that does both correctly. I've a lot of variations to get it working but, no success so far. I've tried several ways to create a selectlist, but somehow it ignores the Selected property. In all my tests, the Selected property was set to true on one item, but this property is just ignored.
So any ideas are most welcome!
This is the latest code that I've tried:
public static IEnumerable<SelectListItem> ToSelectList(Type enumType, string selectedItem)
{
List<SelectListItem> items = new List<SelectListItem>();
foreach (var item in Enum.GetValues(enumType))
{
FieldInfo fi = enumType.GetField(item.ToString());
var attribute = fi.GetCustomAttributes(typeof(DescriptionAttribute), true).FirstOrDefault();
var title = attribute == null ? item.ToString() : ((DescriptionAttribute)attribute).Description;
var listItem = new SelectListItem
{
Value = ((int)item).ToString(),
Text = title,
Selected = selectedItem == item.ToString()
};
items.Add(listItem);
}
return items;
}
public static HtmlString EnumDropDownList2For<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> modelExpression)
{
var typeOfProperty = modelExpression.ReturnType;
if (!typeOfProperty.IsEnum)
throw new ArgumentException(string.Format("Type {0} is not an enum", typeOfProperty));
var value = htmlHelper.ViewData.Model == null
? default(TProperty)
: modelExpression.Compile()(htmlHelper.ViewData.Model);
return htmlHelper.DropDownListFor(modelExpression, ToSelectList(modelExpression.ReturnType, value.ToString()));
}
I had the same issue with enums which actually had custom value set
public enum Occupation
{
[Description("Lorry driver")] LorryDriver = 10,
[Description("The big boss")] Director = 11,
[Description("Assistant manager")] AssistantManager = 12
}
What I found is that when I use DropDownListFor(), it doesn't use the selected item from the SelectListItem collection to set the selected option. Instead it selects an option with a value which equals to the property I'm trying to bind to (m => m.Occupation) and for this it uses the enum's .ToString() not the enum's actual integer value. So what I ended up with is setting the SelectListItem's Value like so:
var listItem = new SelectListItem
{
Value = item.ToString(), // use item.ToString() instead
Text = title,
Selected = selectedItem == item.ToString() // <- no need for this
};
The helper method:
public static class SelectListItemsForHelper
{
public static IEnumerable<SelectListItem> SelectListItemsFor<T>(T selected) where T : struct
{
Type t = typeof(T);
if (t.IsEnum)
{
return Enum.GetValues(t).Cast<Enum>().Select(e => new SelectListItem { Value = e.ToString(), Text = e.GetDescription() });
}
return null;
}
public static string GetDescription<TEnum>(this TEnum value)
{
FieldInfo fi = value.GetType().GetField(value.ToString());
if (fi != null)
{
var attributes = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false);
if (attributes.Length > 0)
return attributes[0].Description;
}
return value.ToString();
}
}
In the view:
#Html.DropDownListFor(m => m.Occupation, SelectListItemsForHelper.SelectListItemsFor(Model.Occupation), String.Empty)
To summarize the solution that does work (at least for me):
I use the following set of helper methods
public static IEnumerable<SelectListItem> ToSelectList(Type enumType, string selectedItem)
{
List<SelectListItem> items = new List<SelectListItem>();
foreach (var item in Enum.GetValues(enumType))
{
var title = item.GetDescription();
var listItem = new SelectListItem
{
Value = item.ToString(),
Text = title,
Selected = selectedItem == item.ToString()
};
items.Add(listItem);
}
return items;
}
public static MvcHtmlString EnumDropDownListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression) where TModel : class
{
string inputName = GetInputName(expression);
var value = htmlHelper.ViewData.Model == null
? default(TProperty)
: expression.Compile()(htmlHelper.ViewData.Model);
return htmlHelper.DropDownList(inputName, ToSelectList(typeof(TProperty), value.ToString()));
}
public static string GetInputName<TModel, TProperty>(Expression<Func<TModel, TProperty>> expression)
{
if (expression.Body.NodeType == ExpressionType.Call)
{
MethodCallExpression methodCallExpression = (MethodCallExpression)expression.Body;
string name = GetInputName(methodCallExpression);
return name.Substring(expression.Parameters[0].Name.Length + 1);
}
return expression.Body.ToString().Substring(expression.Parameters[0].Name.Length + 1);
}
private static string GetInputName(MethodCallExpression expression)
{
MethodCallExpression methodCallExpression = expression.Object as MethodCallExpression;
if (methodCallExpression != null)
{
return GetInputName(methodCallExpression);
}
return expression.Object.ToString();
}
Usage:
#Html.EnumDropDownListFor(m => m.MyEnumType)
This works for enums with or without a description attribute, and sets the correct selected value.

Categories

Resources