如何使枚举默认编辑模板?
-
26-09-2019 - |
题
我怎么能做出一个枚举默认编辑器模板?我的意思是:我可以做这样的事情:
<%@ 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()) %>
有了这个,我就不用做每一个枚举模板了。
解决方案 2
感谢大家的贡献点击
Yngvebn,我以前试过您的解决方案(在你最后的评论),但我没有做的唯一的事情是<dynamic>
,我在泛型类型来代替<Enum>
。
在最后的解决方案是:结果 创建一个名为Enum.acsx模板,并把它在查看\共享\ 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
}
和再有Extention方法:
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;
}
}
其他提示
晚来回答,但我希望这可以帮助别人。理想情况下,你希望所有枚举按照惯例使用您的枚举模板,而不是每次都指定一个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;
}
}
然后,只需在Global.asax.cs中的Application_Start方法中注册它:
ModelMetadataProviders.Current = new CustomMetadataProvider();
现在所有的枚举属性将默认使用您的枚举模板。
下面是本作的辅助我.. 在你看来,你可以简单地做:
<%= 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());
}
您还需要我的重载标签类,如果你想让它工作没有改写..
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;
}
}
努尔Sabony,我修改您的版本也与资源支持本地化。因此,我改变了DescriptionAttribute到DataAnnotations的DisplayAttribute命名空间
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))
希望这可以帮助别人!
我做了dropdownlistfor方法更容易一点,现在你可以给它一个了selectedValue:
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模型及其属性性别包含用于DropDownListFor的了selectedValue。
我不认为有一个默认的方式来定义的所有枚举类型的编辑,因为你可以要根据不同的情况不同的行为。比如,也许你有一个[国旗]枚举,想多选,或者你想有一个下拉列表,或者你想单选按钮。
另外,通常你会需要某种超越你可以在变量的命名限制实现有意义的显示字符串。
当然的分配的以枚举类型的属性开箱的,但你如何得到该值将是由你。
是
几乎肯定这部作品的开箱即用。
尝试命名模板的名称相同的枚举。