2012-02-14 2 views
2

Есть несколько полезных методов расширения для использования отображения перечислений в выпадающих списках. Например, here и here.MVC3 EnumDropdownList выбранное значение

Но есть одна проблема, с которой я сталкиваюсь, что эти помощники не работают, если перечисление украшено атрибутом Description. Первый пример отлично работает с атрибутом Description, но он не устанавливает выбранное значение. Второй пример устанавливает выбранное значение, но он не использует атрибут описания. Поэтому мне нужно объединить оба метода в рабочий помощник, который делает оба правильно. У меня есть много вариантов, чтобы заставить его работать, но пока ничего не получилось. Я пробовал несколько способов создания selectlist, но почему-то игнорирует свойство Selected. Во всех моих тестах свойство Selected было установлено как true для одного элемента, но это свойство просто игнорируется. Так что любые идеи приветствуются!

Это последний код, который я пробовал:

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())); 
    } 
+0

jsut Дополнительная информация: http://coding-in.net/asp-net-mvc-3-method-extension/ – mbowles

ответ

3

Я была такая же проблема с перечислениями, которые фактически имели обычай значение, установленное

public enum Occupation 
{ 
    [Description("Lorry driver")] LorryDriver = 10, 
    [Description("The big boss")] Director = 11, 
    [Description("Assistant manager")] AssistantManager = 12 
} 

То, что я обнаружил, что, когда я использую DropDownListFor(), он не использует выбранный элемент из коллекции SelectListItem для установки выбранной опции. Вместо этого он выбирает параметр со значением, равным значению, которое я пытаюсь связать с (m => m.Occupation), и для этого он использует значение enum .ToString(), а не фактическое целочисленное значение enum. Так что я в конечном итоге с устанавливает значение в SelectListItem как так:

var listItem = new SelectListItem 
{ 
    Value = item.ToString(), // use item.ToString() instead 
    Text = title, 
    Selected = selectedItem == item.ToString() // <- no need for this 
}; 

Вспомогательный метод:

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(); 
    } 
} 

По мнению:

@Html.DropDownListFor(m => m.Occupation, SelectListItemsForHelper.SelectListItemsFor(Model.Occupation), String.Empty) 
+0

Благодарим вас за ответ. Даже несмотря на то, что вы код для меня действительно не работает, это помогло мне решить проблему! Я все еще не уверен, что в итоге сделал трюк. Я изменил свою функцию ToSelectList в соответствии с вашими комментариями и объединил ее с методом GetDescription. – Hanno

1

Резюмируя решение, которое делает работу (по крайней мере, для меня):

Я использую следующий набор вспомогательных методов:

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(); 
    } 

Использование:

@Html.EnumDropDownListFor(m => m.MyEnumType) 

Это работает для перечислений с или без атрибута описания, и устанавливает правильное выбранное значение.

+0

Вам не хватает GetDescription() (легко копируется из Zeno выше), но 'htmlHelper.DropDownList' не определен в моем проекте MVC3, а VS не имеет представления о том, где я могу его найти (я уже' использую System.Web. Mvc'), поэтому я не уверен, в чем проблема. Что такое пространство имен для этого метода? –

Смежные вопросы