/// <summary>
/// DropDownListFor model property which has AllowedValuesAttribute
/// </summary>
/// <typeparam name="TModel">Model to create a dropdown for</typeparam>
/// <param name="helper">HTML Helper</param>
/// <param name="expression">Expression to use</param>
/// <param name="htmlAttributes">Attributes to use</param>
/// <returns>MVC Html String of Dropdownlist</returns>
public static MvcHtmlString DropDownListFor<TModel>(this HtmlHelper<TModel> helper, Expression<Func<TModel, object>> expression, object htmlAttributes)
{
ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, helper.ViewData);
var info = GetPropertyInformation(expression.Body);
if (info == null) return helper.DropDownListFor(expression, htmlAttributes);
var attr = info.GetAttribute<AllowedValuesAttribute>(true);
if (attr == null) return helper.DropDownListFor(expression, htmlAttributes);
IEnumerable<SelectListItem> items =
attr.Values.Select(
value => new SelectListItem() { Text = value, Value = value, Selected = value.Equals(metadata.Model) });
return helper.DropDownListFor(expression, items, htmlAttributes);
}
/// <summary>
/// Gets property information
/// </summary>
/// <param name="expression">Expression to use</param>
/// <returns>Member info of property</returns>
public static MemberInfo GetPropertyInformation(Expression expression)
{
var member = expression as MemberExpression;
if (member == null)
{
var unary = expression as UnaryExpression;
if (unary != null && unary.NodeType == ExpressionType.Convert)
{
member = unary.Operand as MemberExpression;
}
}
if (member != null && member.Member.MemberType == MemberTypes.Property)
{
return member.Member;
}
return null;
}
/// <summary>
/// Attempts to get attribute from an object
/// </summary>
/// <typeparam name="T">Attribute to get</typeparam>
/// <param name="member">Member to get attribute from</param>
/// <param name="isRequired">Is the attribute required</param>
/// <returns>Required attribute</returns>
public static T GetAttribute<T>(this MemberInfo member, bool isRequired) where T : Attribute
{
var attribute = member.GetCustomAttributes(typeof(T), false).SingleOrDefault();
if (attribute == null && isRequired) return null;
return (T)attribute;
}
// Usage:
// [AttributeUsage("Option1", "Option2", "Option3")]
// public string MyTestAttribute { get; set; }
//
// In view:
// @Html.DropDownListFor(x => x.MyTestAttribute)
//
// Result:
// Dropdown list with 3 options.
namespace Extensions
{
using System;
using System.ComponentModel.DataAnnotations;
using System.Linq;
/// <summary>
/// AllowedValues attribute for string types
/// </summary>
[AttributeUsage(AttributeTargets.Property, Inherited = false)]
public sealed class AllowedValuesAttribute : ValidationAttribute
{
public AllowedValuesAttribute(params string[] args)
{
Values = args;
}
public string[] Values { get; set; }
public override bool IsValid(object value)
{
if (Values.Contains(value))
return true;
return false;
}
}
}