2014-11-25 2 views
27

У меня есть список перечислений, которые я использую для страницы управления пользователями. Я использую новый HtmlHelper в MVC 5.1, который позволяет мне создать раскрывающийся список для значений Enum. Теперь мне нужно удалить значение Pending из списка, это значение будет только когда-либо задано программно и никогда не должно быть установлено пользователем.Исключить/удалить значение из MVC 5.1 EnumDropDownListFor

Enum:

public enum UserStatus 
{ 
    Pending = 0, 
    Limited = 1, 
    Active = 2 
} 

Вид:

@Html.EnumDropDownListFor(model => model.Status) 

Есть в любом случае, либо перекрывая текущий контроль, или написать собственный HtmlHelper, который позволил бы мне задать перечисление или перечислений, чтобы исключить из результирующего списка? Или вы предлагаете мне сделать что-то клиентское с jQuery, чтобы удалить значение из раскрывающегося списка после его создания?

Спасибо!

+0

Вы можете скопировать исходный код MVC для 'EnumDropDownListFor' [здесь] (https://aspnetwebstack.codeplex.com/SourceControl/latest#src/System.Web.Mvc/Html/SelectExtensions.cs) и [здесь] (https://aspnetwebstack.codeplex.com/SourceControl/latest#src/System.Web.Mvc/Html/EnumHelper.cs) и изменить подпись, чтобы включить параметр, представляющий собой набор исключенных значений, а затем в 'EnumHelper .GetSelectList() ', игнорировать элементы, которые находятся в исключенных значениях. –

ответ

33

Вы могли бы построить выпадающий список:

@{ // you can put the following in a back-end method and pass through ViewBag 
    var selectList = Enum.GetValues(typeof(UserStatus)) 
         .Cast<UserStatus>() 
         .Where(e => e != UserStatus.Pending) 
         .Select(e => new SelectListItem 
          { 
           Value = ((int)e).ToString(), 
           Text = e.ToString() 
          }); 
} 
@Html.DropDownListFor(m => m.Status, selectList) 
+0

Это сработало отлично, но когда я попытался переместить код на задний план и передать его с помощью Viewbag, возникла ошибка, говорящая о том, что она не может содержать динамически сконструированное содержимое. Я предполагаю, что это связано с тем, что Viewbag динамически создается во время выполнения, перемещая код в View, сортируя проблему, и я вижу, что правильное значение передается обратно в POST. Благодаря! :) –

+4

В задней части дела 'ViewBag.SelectList = selectList;' и в начале дела '@ Html.DropDownListFor (m => m.Status, (IEnumerable ) ViewBag.SelectList)' должен работать (из памяти !) –

+0

Ваша память была верна! Значит, это был бросок перед Viewbag, который отсутствовал, когда я попытался это сделать в первый раз? Я предполагаю, что это говорит о Razor View, что ожидать, когда элемент Viewbag был создан? –

4

Вы можете создать раскрывающееся меню на looping through the values in the enum и включить только <option>, если оно не находится на рассмотрении.

Вот как это должно работать, но, как вы можете видеть, я не уверен, что вы будете использовать для значения или текста тега параметра.

<select> 
foreach (var status in Enum.GetValues(typeof(UserStatus))) 
{ 
    if(status != UserStatus.Pending) 
    { 
     <option value="status.???">@status.???</option> 
    } 
} 
</select> 
19

Измененный @ dav_i отвечают.

Это не идеально, но это то, что я использую. Ниже приведено расширение до HtmlHelper. Метод расширения будет выглядеть как EnumDropDownListFor из ASP.NET и использовать DisplayAttribute, если применяется значение Enum.

/// <summary> 
/// Returns an HTML select element for each value in the enumeration that is 
/// represented by the specified expression and predicate. 
/// </summary> 
/// <typeparam name="TModel">The type of the model.</typeparam> 
/// <typeparam name="TEnum">The type of the value.</typeparam> 
/// <param name="htmlHelper">The HTML helper instance that this method extends.</param> 
/// <param name="expression">An expression that identifies the object that contains the properties to display.</param> 
/// <param name="optionLabel">The text for a default empty item. This parameter can be null.</param> 
/// <param name="predicate">A <see cref="Func{TEnum, bool}"/> to filter the items in the enums.</param> 
/// <param name="htmlAttributes">An object that contains the HTML attributes to set for the element.</param> 
/// <returns>An HTML select element for each value in the enumeration that is represented by the expression and the predicate.</returns> 
/// <exception cref="ArgumentNullException">If expression is null.</exception> 
/// <exception cref="ArgumentException">If TEnum is not Enum Type.</exception> 
public static MvcHtmlString EnumDropDownListFor<TModel, TEnum>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TEnum>> expression, Func<TEnum, bool> predicate, string optionLabel, object htmlAttributes) where TEnum : struct, IConvertible 
{ 
    if (expression == null) 
    { 
     throw new ArgumentNullException("expression"); 
    } 

    if (!typeof(TEnum).IsEnum) 
    { 
     throw new ArgumentException("TEnum"); 
    } 

    ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData); 
    IList<SelectListItem> selectList = Enum.GetValues(typeof(TEnum)) 
      .Cast<TEnum>() 
      .Where(e => predicate(e)) 
      .Select(e => new SelectListItem 
       { 
        Value = Convert.ToUInt64(e).ToString(), 
        Text = ((Enum)(object)e).GetDisplayName(), 
       }).ToList(); 
    if (!string.IsNullOrEmpty(optionLabel)) { 
     selectList.Insert(0, new SelectListItem { 
      Text = optionLabel, 
     }); 
    } 

    return htmlHelper.DropDownListFor(expression, selectList, htmlAttributes); 
} 

/// <summary> 
/// Gets the name in <see cref="DisplayAttribute"/> of the Enum. 
/// </summary> 
/// <param name="enumeration">A <see cref="Enum"/> that the method is extended to.</param> 
/// <returns>A name string in the <see cref="DisplayAttribute"/> of the Enum.</returns> 
public static string GetDisplayName(this Enum enumeration) 
{ 
    Type enumType = enumeration.GetType(); 
    string enumName = Enum.GetName(enumType, enumeration); 
    string displayName = enumName; 
    try 
    { 
     MemberInfo member = enumType.GetMember(enumName)[0]; 

     object[] attributes = member.GetCustomAttributes(typeof(DisplayAttribute), false); 
     DisplayAttribute attribute = (DisplayAttribute)attributes[0]; 
     displayName = attribute.Name; 

     if (attribute.ResourceType != null) 
    { 
      displayName = attribute.GetName(); 
     } 
    } 
    catch { } 
    return displayName; 
} 

Например:

@Html.EnumDropDownListFor(
    model => model.UserStatus, 
    (userStatus) => { return userStatus != UserStatus.Active; }, 
    null, 
    htmlAttributes: new { @class = "form-control" }); 

Это создаст выпадающий список Enum без опции Active.

+0

Brilliant - Это происходит в моей библиотеке фрагментов :) Кстати, вам не нужно возвращать условие, которое вы могли бы просто поставить (userStatus) => userStatus! = UserStatus.Active – heymega

+0

Единственное, что нужно использовать в представлении, - это выражение 'using' для класса, где это определено. Отлично. :-) – podvlada

0

Ниже приведено расширение к HtmlHelper. Он очень похож на расширение EnumDropDownListFor из ASP.NET, но он сортирует SelectListItem с помощью отображаемого имени элемента. У этого есть наводящее на размышления имя: SortedEnumDropDownListFor не конфликтует с исходным расширением.

/// <summary> 
    /// 
    /// </summary> 
    /// <typeparam name="TModel">The type of the model.</typeparam> 
    /// <typeparam name="TEnum">The type of the value.</typeparam> 
    /// <param name="htmlHelper">The HTML helper instance that this method extends.</param> 
    /// <param name="expression">An expression that identifies the object that contains the properties to display</param> 
    /// <param name="initalValue">The unselected item initial value</param> 
    /// <param name="htmlAttributes"></param> 
    /// <returns></returns> 
    public static MvcHtmlString SortedEnumDropDownListFor<TModel, TEnum>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TEnum>> expression, string initalValue, object htmlAttributes = null) 
    { 

     ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData); 

     Type enumType = GetNonNullableModelType(metadata); 
     Type baseEnumType = Enum.GetUnderlyingType(enumType); 
     List<SelectListItem> items = new List<SelectListItem>(); 

     foreach (FieldInfo field in enumType.GetFields(BindingFlags.Static | BindingFlags.GetField | BindingFlags.Public)) 
     { 
      string text = field.Name; 
      string value = Convert.ChangeType(field.GetValue(null), baseEnumType).ToString(); 
      bool selected = field.GetValue(null).Equals(metadata.Model); 

      foreach (DisplayAttribute displayAttribute in field.GetCustomAttributes(true).OfType<DisplayAttribute>()) 
      { 
       text = displayAttribute.GetName(); 
      } 

      items.Add(new SelectListItem 
      { 
       Text = text, 
       Value = value, 
       Selected = selected 
      }); 
     } 

     items = new List<SelectListItem>(items.OrderBy(s => s.Text)); 
     items.Insert(0, new SelectListItem { Text = initalValue, Value = "" }); 

     return htmlHelper.DropDownListFor(expression, items, htmlAttributes); 

    }   

    private static Type GetNonNullableModelType(ModelMetadata modelMetadata) 
    { 
     Type realModelType = modelMetadata.ModelType; 
     Type underlyingType = Nullable.GetUnderlyingType(realModelType); 

     if (underlyingType != null) 
     { 
      realModelType = underlyingType; 
     } 

     return realModelType; 
    } 

Если вы не хотите возиться с неактивной intitia пункт, просто построить перегрузки, как это:

public static MvcHtmlString SortedEnumDropDownListFor<TModel, TEnum>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TEnum>> expression, object htmlAttributes = null) 
     { 
      MvcHtmlString helper = SortedEnumDropDownListFor(htmlHelper, expression, string.Empty, htmlAttributes); 
      return helper; 
     } 

И вы хорошо идти. Я надеюсь, что это помогает.

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