Подтвердить что ты не робот

Как создать шаблон редактора по умолчанию для перечислений?

Как создать шаблон редактора по умолчанию для перечислений? Под этим я имею в виду: могу ли я сделать что-то вроде этого:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<Enum>" %> 
<% -- any code to read the enum and write a dropdown -->

И поместите это в папку EditorTemplates под именем Enum.ascx?

Вот обходной путь для моей проблемы, который я пробовал, но это не то, что мне нужно.

Вот мое перечисление:

public enum GenderEnum
{
    /// <summary>
    /// Male
    /// </summary>
    [Description("Male Person")]
    Male,

    /// <summary>
    /// Female
    /// </summary>
    [Description("Female Person")]
    Female
}

Я создал шаблон под названием GenderEnum.acsx и поместил его в папку Shared/EditorTemplates. Вот шаблон:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<AlefTech.HumanResource.Core.GenderEnum>" %>
<%@ Import Namespace="AlefTech.HumanResource.WebModule.Classes" %>
<%=Html.DropDownListFor(m => m.GetType().Name, Model.GetType()) %>

Конечно, метод мой:

public static class HtmlHelperExtension
    {
        public static MvcHtmlString DropDownListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, Type enumType)
        {
            List<SelectListItem> list = new List<SelectListItem>();
            Dictionary<string, string> enumItems = enumType.GetDescription();
            foreach (KeyValuePair<string, string> pair in enumItems)
                list.Add(new SelectListItem() { Value = pair.Key, Text = pair.Value });
            return htmlHelper.DropDownListFor(expression, list);
        }

        /// <summary>
        /// return the items of enum paired with its descrtioption.
        /// </summary>
        /// <param name="enumeration">enumeration type to be processed.</param>
        /// <returns></returns>
        public static Dictionary<string, string> GetDescription(this Type enumeration)
        {
            if (!enumeration.IsEnum)
            {
                throw new ArgumentException("passed type must be of Enum type", "enumerationValue");
            }

            Dictionary<string, string> descriptions = new Dictionary<string, string>();
            var members = enumeration.GetMembers().Where(m => m.MemberType == MemberTypes.Field);

            foreach (MemberInfo member in members)
            {
                var attrs = member.GetCustomAttributes(typeof(DescriptionAttribute), false);
                if (attrs.Count() != 0)
                    descriptions.Add(member.Name, ((DescriptionAttribute)attrs[0]).Description);
            }
            return descriptions;
        }

    }

Однако, хотя это сработало для меня, я не об этом спрашиваю. Вместо этого мне нужно следующее:

Код для Shared\EditorTemplates\Enum.acsx:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<Enum>" %>
<%@ Import Namespace="System.Web.Mvc.Html" %>
<%@ Import Namespace="WhereMyExtentionMethod" %>
<%=Html.DropDownListFor(m => m.GetType().Name, Model.GetType()) %>

С этим мне больше не придется создавать шаблон для каждого перечисления.

4b9b3361

Ответ 1

Спасибо всем за ваш вклад
Yngvebn, я пробовал ваше решение (в вашем последнем комментарии) раньше, но единственное, чего я не делал, это <dynamic>, я использовал вместо <Enum> в родовом типе.

наконец решение:
создайте шаблон с именем Enum.acsx и поместите его под Views\Shared\EditorTemplates

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<dynamic>" %>
<%@ Import Namespace="System.Web.Mvc.Html" %>
<%@ Import Namespace="the extension methods namespace" %>
<% Enum model = (Enum)Model; %>
<%=Html.DropDownList(model.GetType().Name,model.GetType())%>

и в вашем объекте:

public class Person
{
  [UIHint("Enum")]
  public GenderEnum Gender{get;set;}
}

public Enum GenderEnum
{
 [Description("Male Person")]
 Male,
 [Description("Female Person")]
 Female
}

и снова есть методы расширения:

public static class HtmlHelperExtension
    {
        public static MvcHtmlString DropDownListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, Type enumType)
        {
            List<SelectListItem> list = new List<SelectListItem>();
            Dictionary<string, string> enumItems = enumType.GetDescription();
            foreach (KeyValuePair<string, string> pair in enumItems)
                list.Add(new SelectListItem() { Value = pair.Key, Text = pair.Value });
            return htmlHelper.DropDownListFor(expression, list);
        }

        /// <summary>
        /// return the items of enum paired with its descrtioption.
        /// </summary>
        /// <param name="enumeration">enumeration type to be processed.</param>
        /// <returns></returns>
        public static Dictionary<string, string> GetDescription(this Type enumeration)
        {
            if (!enumeration.IsEnum)
            {
                throw new ArgumentException("passed type must be of Enum type", "enumerationValue");
            }

            Dictionary<string, string> descriptions = new Dictionary<string, string>();
            var members = enumeration.GetMembers().Where(m => m.MemberType == MemberTypes.Field);

            foreach (MemberInfo member in members)
            {
                var attrs = member.GetCustomAttributes(typeof(DescriptionAttribute), false);
                if (attrs.Count() != 0)
                    descriptions.Add(member.Name, ((DescriptionAttribute)attrs[0]).Description);
            }
            return descriptions;
        }

    }

Ответ 2

Поздно, но я надеюсь, что это поможет другим. В идеале вы хотите, чтобы все перечисления использовали шаблон Enum по соглашению, а не путем указания UIHint каждый раз, и вы можете это сделать, создав собственный поставщик метаданных модели, например:

using System;
using System.Collections.Generic;
using System.Web.Mvc;

public class CustomMetadataProvider : DataAnnotationsModelMetadataProvider
{
    protected override ModelMetadata CreateMetadata(IEnumerable<Attribute> attributes, Type containerType, Func<object> modelAccessor, Type modelType, string propertyName) {
        var mm = base.CreateMetadata(attributes, containerType, modelAccessor, modelType, propertyName);
        if (modelType.IsEnum && mm.TemplateHint == null) {
            mm.TemplateHint = "Enum";
        }
        return mm;
    }
}

Затем просто зарегистрируйте его в методе Application_Start для Global.asax.cs:

ModelMetadataProviders.Current = new CustomMetadataProvider();

Теперь все ваши свойства перечисления будут использовать шаблон Enum по умолчанию.

Ответ 3

Вот помощник, который я сделал для этого. В вашем представлении вы можете просто:

<%= Html.DropDownForEnum<MyEnum>("some-name-for-dropdown", MyEnum.TheFirstValue) %>

для текста в фактическом выпадающем списке он будет искать Ресурс в файле ресурсов, который соответствует имени перечисления, иначе просто напишите фактический сам Enumtext.

public static MvcHtmlString DropDownForEnum<T>(this HtmlHelper h, string name, T selectedValue)
{
    Type enumType = typeof(T);
    Tag t = new Tag("select").With("name", name).And("id", name);

    foreach (T val in Enum.GetValues(enumType))
    {
        string enumText = Resources.ResourceManager.GetString(val.ToString());
        if (String.IsNullOrEmpty(enumText)) enumText = val.ToString();
        Tag option = new Tag("option").With("value", (val).ToString()).AndIf(val.Equals(selectedValue), "selected", "selected").WithText(enumText);
        t.Append(option);
    }
    return MvcHtmlString.Create(t.ToString());
}

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

public class Tag : TagBuilder
{
public Tag (string TagName): base(TagName)
{

}

public Tag Append(Tag innerTag)
{
    base.InnerHtml += innerTag.ToString();
    return this;
}

public Tag WithText(string text)
{

    base.InnerHtml += text;
    return this;
}

public Tag With(Tag innerTag)
{
    base.InnerHtml = innerTag.ToString();
    return this;
}

public Tag With(string attributeName, string attributeValue)
{
    base.Attributes.Add(attributeName, attributeValue);
    return this;
}

public Tag And(string attributeName, string attributeValue)
{
    base.Attributes.Add(attributeName, attributeValue);
    return this;
}


public Tag AndIf(bool condition, string attributeName, string attributeValue)
{
    if(condition)
        base.Attributes.Add(attributeName, attributeValue);
    return this;
}
}

Ответ 4

Nour Sabony, я изменил вашу версию, чтобы также поддерживать локализацию ресурсов. Поэтому я изменил атрибут DescriptionAttribute на DisplayAttribute пространства имен DataAnnotations

    public static MvcHtmlString DropDownListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, Type enumType)
    {
        List<SelectListItem> list = new List<SelectListItem>();
        Dictionary<string, string> enumItems = enumType.GetDisplayNames(htmlHelper.ViewContext.HttpContext);
        foreach (KeyValuePair<string, string> pair in enumItems)
            list.Add(new SelectListItem() { Value = pair.Key, Text = pair.Value });
        return htmlHelper.DropDownListFor(expression, list);
    }

    /// <summary>
    /// return the items of enum paired with its DisplayName.
    /// </summary>
    /// <param name="enumeration">enumeration type to be processed.</param>
    /// <returns></returns>
    public static Dictionary<string, string> GetDisplayNames(this Type enumeration, HttpContextBase httpContext)
    {
        if (!enumeration.IsEnum)
        {
            throw new ArgumentException("passed type must be of Enum type", "enumerationValue");
        }

        Dictionary<string, string> displayNames = new Dictionary<string, string>();
        var members = enumeration.GetMembers().Where(m => m.MemberType == MemberTypes.Field);

        foreach (MemberInfo member in members)
        {
            var attrs = member.GetCustomAttributes(typeof(DisplayAttribute), false);
            if (attrs.Count() != 0)
                if (((DisplayAttribute)attrs[0]).ResourceType != null)
                {
                    displayNames.Add(member.Name, ((DisplayAttribute)attrs[0]).GetName(););
                }
                else
                {
                    displayNames.Add(member.Name, ((DisplayAttribute)attrs[0]).Name);
                }
        }
        return displayNames;
    }

Определение перечисления должно выглядеть следующим образом:

public enum Gender
{
    [Display(Name = "Male", ResourceType = typeof(mynamespace.App_LocalResources.Shared))]
    Male = 1,

    [Display(Name = "Female", ResourceType = typeof(mynamespace.App_LocalResources.Shared))]
    Female = 2,

}

он может использоваться в представлении таким же образом, например. (Бритва):

@Html.DropDownListFor(model => model.Gender, typeof(Gender))

Надеюсь, это поможет кому-то!

Ответ 5

Я сделал метод dropdownlist для метода немного проще, и теперь вы можете дать ему выделенное значение:

public static MvcHtmlString DropDownListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, Type enumType)
{
    return DropDownListFor(htmlHelper, expression, enumType, null);
}

public static MvcHtmlString DropDownListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, Type enumType, object selectedValue)
{
    Dictionary<string, string> enumItems = enumType.GetDisplayNames(htmlHelper.ViewContext.HttpContext);
    return htmlHelper.DropDownListFor(expression, new SelectList(enumItems, "Key", "Value", selectedValue));
}

Используйте его так, как показано на рисунке:

@Html.DropDownListFor(m => m.Gender, typeof(Gender), Model.Gender)

Модель - это моя MVC-модель, а ее свойство Gender содержит выбранное значение для DropDownListFor.

Ответ 6

Я не думаю, что существует способ по умолчанию для определения редактора для всех типов перечислений, потому что вы можете захотеть другого поведения в зависимости от ситуации. Например, возможно, у вас есть перечисление [Flags] и хотите выбрать multi, или вы хотите выпадающий список, или хотите переключатели.

Плюс, как правило, вам понадобится какая-то значимая строка отображения за пределами того, что вы можете выполнить в ограничениях имен имен переменных.

Конечно, присвоение свойства типа enum работает из коробки, но как вы получите это значение, будет вам.

Ответ 7

Вы можете использовать этот пример.....

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Profile.Data.Enum
{
    public enum EfficiencyType
    {
        Good = 1,
        Excelent = 2,
        Better = 3
    }
}

метод расширения...

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Html;

namespace Profile.Web.HtmlHelper
{
    public static class EnumDropDownList
    {
        public static HtmlString EnumDropDownListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> modelExpression, string firstElement)
        {
            var typeOfProperty = modelExpression.ReturnType;
            if (!typeOfProperty.IsEnum)
            throw new ArgumentException(string.Format("Type {0} is not an enum", typeOfProperty));

            var enumValues = new SelectList(Enum.GetValues(typeOfProperty));
            return htmlHelper.DropDownListFor(modelExpression, enumValues, firstElement);
        }
    }
}

а html -....

@Html.DropDownListFor(model => model.EfficiencyType, new SelectList(Enum.GetValues(typeof(EfficiencyType)), Model.EfficiencyType), "--Select--")

Ответ 8

Да

Почти уверен, что это работает из коробки.


Попробуйте называть ваш шаблон тем же именем, что и ваше перечисление.