私は、EnumをDropDownsにバインドする一般的な方法がヘルパーメソッドを介して行われることを、どこでも見つけてきました。
ASP.Net MVC 4でEnumをDropDownListsにバインドする最良の方法は何ですか?
私はそれが唯一の(きれいな)方法であり、残念なことだと思いますが、少なくともいくつかの選択肢があります。このブログをご覧になることをお勧めします: http://paulthecyclist.com/2013/05/24/enum-dropdown/
申し訳ありませんが、ここでコピーするには長すぎますが、要点は彼がこのための新しいHTMLヘルパーメソッドを作成したことです。
すべてのソースコードは GitHub で入手できます。
これができます:
@Html.DropDownListFor(model => model.Type, Enum.GetNames(typeof(Rewards.Models.PropertyType)).Select(e => new SelectListItem { Text = e }))
MVC 5.1以降、列挙型はフレームワークでサポートされています。
@Html.EnumDropDownListFor(m => m.Palette)
表示されるテキストはカスタマイズできます。
public enum Palette
{
[Display(Name = "Black & White")]
BlackAndWhite,
Colour
}
MSDNリンク: http://www.asp.net/mvc/overview/releases/mvc51-release-notes#Enum
私のコントローラーで:
var feedTypeList = new Dictionary<short, string>();
foreach (var item in Enum.GetValues(typeof(FeedType)))
{
feedTypeList.Add((short)item, Enum.GetName(typeof(FeedType), item));
}
ViewBag.FeedTypeList = new SelectList(feedTypeList, "Key", "Value", feed.FeedType);
私からしてみれば:
@Html.DropDownList("FeedType", (SelectList)ViewBag.FeedTypeList)
技術的には、Html.DropdownListFor
はSelectList
またはIenumerable<SelectListItem>
のみを必要とするため、ヘルパーメソッドは必要ありません。列挙型をそのような出力に変換し、その方法でフィードするだけです。
静的ライブラリメソッドを使用して、いくつかのパラメーター/オプションを使用して列挙型をList<SelectListItem>
に変換します。
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 class EnumUtil
{
public static IEnumerable<T> GetEnumValuesFor<T>()
{
return Enum.GetValues(typeof(T)).Cast<T>();
}
// other stuff in here too...
}
/// <summary>
/// Turns Camelcase or underscore separated phrases into properly spaces phrases
/// "DogWithMustard".ToFriendlyString() == "Dog With Mustard"
/// </summary>
public static string ToFriendlyString(this object o)
{
var s = o.ToString();
s = s.Replace("__", " / ").Replace("_", " ");
char[] origArray = s.ToCharArray();
List<char> newCharList = new List<char>();
for (int i = 0; i < origArray.Count(); i++)
{
if (origArray[i].ToString() == origArray[i].ToString().ToUpper())
{
newCharList.Add(' ');
}
newCharList.Add(origArray[i]);
}
s = new string(newCharList.ToArray()).TrimStart();
return s;
}
ViewModelは、必要なオプションを渡すことができます。これはかなり複雑なものです:
public IEnumerable<SelectListItem> PaymentMethodChoices
{
get
{
var exclusions = new List<Membership.Payment.PaymentMethod> { Membership.Payment.PaymentMethod.Unknown, Membership.Payment.PaymentMethod.Reversal };
var selected = new List<Membership.Payment.PaymentMethod> { this.SelectedPaymentMethod };
return GetEnumsByType<Membership.Payment.PaymentMethod>(useFriendlyName: true, exclude: exclusions, eachSelected: selected);
}
}
そのため、ビューのDropDownList
をそのIEnumerable<SelectListItem>
プロパティに対して配線します。
PaulTheCyclistのソリューションが注目されています。しかし、RESXは使用しません(新しい列挙型ごとに新しい.resxファイルを追加する必要がありますか?)
これが私のHtmlHelper式です。
public static MvcHtmlString EnumDropDownListFor<TModel, TEnum>(this HtmlHelper<TModel> htmlHelper,
Expression<Func<TModel, TEnum>> expression, object attributes = null)
{
//Get metadata from enum
var metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
var enumType = GetNonNullableModelType(metadata);
var values = Enum.GetValues(enumType).Cast<TEnum>();
//Convert enumeration items into SelectListItems
var items =
from value in values
select new SelectListItem
{
Text = value.ToDescription(),
Value = value.ToString(),
Selected = value.Equals(metadata.Model)
};
//Check for nullable value types
if (metadata.IsNullableValueType)
{
var emptyItem = new List<SelectListItem>
{
new SelectListItem {Text = string.Empty, Value = string.Empty}
};
items = emptyItem.Concat(items);
}
//Return the regular DropDownlist helper
return htmlHelper.DropDownListFor(expression, items, attributes);
}
列挙型を宣言する方法は次のとおりです。
[Flags]
public enum LoanApplicationType
{
[Description("Undefined")]
Undefined = 0,
[Description("Personal Loan")]
PersonalLoan = 1,
[Description("Mortgage Loan")]
MortgageLoan = 2,
[Description("Vehicle Loan")]
VehicleLoan = 4,
[Description("Small Business")]
SmallBusiness = 8,
}
そして、これはRazor Viewからの呼び出しです:
<div class="control-group span2">
<div class="controls">
@Html.EnumDropDownListFor(m => m.LoanType, new { @class = "span2" })
</div>
</div>
どこ@Model.LoanType
はLoanApplicationTypeタイプのモデルプロパティです
PDATE:申し訳ありませんが、ヘルパー関数ToDescription()のコードを忘れてしまいました
/// <summary>
/// Returns Description Attribute information for an Enum value
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public static string ToDescription(this Enum value)
{
if (value == null)
{
return string.Empty;
}
var attributes = (DescriptionAttribute[]) value.GetType().GetField(
Convert.ToString(value)).GetCustomAttributes(typeof (DescriptionAttribute), false);
return attributes.Length > 0 ? attributes[0].Description : Convert.ToString(value);
}
HTMLヘルパーを拡張してうまく機能しますが、DisplayAttributeマッピングに基づいてドロップダウン値のテキストを変更したい場合は、これと同様に変更する必要があります。
(これはMVC 5.1より前に実行し、5.1 +に含まれています)
public static IHtmlString EnumDropDownListFor<TModel, TEnum>(this HtmlHelper<TModel> html, Expression<Func<TModel, TEnum>> expression)
{
var metadata = ModelMetadata.FromLambdaExpression(expression, html.ViewData);
var enumType = Nullable.GetUnderlyingType(metadata.ModelType) ?? metadata.ModelType;
var enumValues = Enum.GetValues(enumType).Cast<object>();
var items = enumValues.Select(item =>
{
var type = item.GetType();
var member = type.GetMember(item.ToString());
var attribute = member[0].GetCustomAttribute<DisplayAttribute>();
string text = attribute != null ? ((DisplayAttribute)attribute).Name : item.ToString();
string value = ((int)item).ToString();
bool selected = item.Equals(metadata.Model);
return new SelectListItem
{
Text = text,
Value = value,
Selected = selected
};
});
return html.DropDownListFor(expression, items, string.Empty, null);
}