ASP .Net核心自定义标记助手将CamelCase属性转换为空格

时间:2017-03-20 13:58:57

标签: asp.net-mvc razor asp.net-core tag-helpers asp.net-core-tag-helpers

在ASP.Net Core中是否可以自动转换视图模型中的驼峰大小写属性名称,以便在使用标记帮助程序时将空格插入相应的标签中?

如果我的视图模型看起来像这样......

[Display(Name = "First Name")]
public string FirstName { get; set; }

[Display(Name = "Last Name")]
public string LastName { get; set; }

[Display(Name = "Referral Date")]
public DateTime ReferralDate { get; set; }

似乎有很多额外的配置应用数据注释,如

  

[显示(姓名="名字")]

只需在单词之间插入空格即可。默认情况下,Tag Helpers会插入空格以避免这种手动配置和潜在的拼写错误。

如果没有,自定义标签帮助器可以在这种情况下提供帮助,如果是这样,它将如何工作?

3 个答案:

答案 0 :(得分:2)

您可以通过构建和注册自定义显示元数据提供程序来实现此目的。有些图书馆将进行更精细的人性化和#34;对于属性名称,但是你可以用一些可信的正则表达式来实现非常有用的东西。

public class HumanizerMetadataProvider : IDisplayMetadataProvider
{
    public void CreateDisplayMetadata(DisplayMetadataProviderContext context)
    {
        var propertyAttributes = context.Attributes;
        var modelMetadata = context.DisplayMetadata;
        var propertyName = context.Key.Name;

        if (IsTransformRequired(propertyName, modelMetadata, propertyAttributes))
        {
            modelMetadata.DisplayName = () => SplitCamelCase(propertyName);
        }
    }

    private static string SplitCamelCase(string str)
    {
        return Regex.Replace(
            Regex.Replace(
                str,
                @"(\P{Ll})(\P{Ll}\p{Ll})",
                "$1 $2"
            ),
            @"(\p{Ll})(\P{Ll})",
            "$1 $2"
        );
    }

    private static bool IsTransformRequired(string propertyName, DisplayMetadata modelMetadata, IReadOnlyList<object> propertyAttributes)
    {
        if (!string.IsNullOrEmpty(modelMetadata.SimpleDisplayProperty))
            return false;

        if (propertyAttributes.OfType<DisplayNameAttribute>().Any())
            return false;

        if (propertyAttributes.OfType<DisplayAttribute>().Any())
            return false;

        if (string.IsNullOrEmpty(propertyName))
            return false;

        return true;
    }
}

IsTransformRequired方法确保您仍然可以在需要时使用装饰属性覆盖提供程序。

通过AddMvcOptions上的IMvcBuilder方法在启动时注册提供商:

builder.AddMvcOptions(m => m.ModelMetadataDetailsProviders.Add(new HumanizerMetadataProvider()));

答案 1 :(得分:2)

如果您只关心 标签 ,则可以轻松覆盖 LabelTagHelper

[HtmlTargetElement("label", Attributes = "title-case-for")]
public class TitleCaseTagHelper : LabelTagHelper
{
    public TitleCaseTagHelper(IHtmlGenerator generator) : base(generator)
    {
    }

    [HtmlAttributeName("title-case-for")]
    public new ModelExpression For { get; set; }

    public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
    {
        if (context == null)
            throw new ArgumentNullException("context");
        if (output == null)
            throw new ArgumentNullException("output");

        string name = For.ModelExplorer.Metadata.DisplayName ?? For.ModelExplorer.Metadata.PropertyName;
        name = name.Humanize(LetterCasing.Title);
        TagBuilder tagBuilder = this.Generator.GenerateLabel(
            this.ViewContext,
            this.For.ModelExplorer,
            this.For.Name,
            name,
            (object) null);
        if (tagBuilder == null)
            return;
        output.MergeAttributes(tagBuilder);
        if (output.IsContentModified)
            return;
        TagHelperContent childContentAsync = await output.GetChildContentAsync();
        if (childContentAsync.IsEmptyOrWhiteSpace)
            output.Content.SetHtmlContent((IHtmlContent) tagBuilder.InnerHtml);
        else
            output.Content.SetHtmlContent((IHtmlContent) childContentAsync);
    }
}

用法

<label title-case-for="RememberMe" class="col-md-2 control-label"></label>

请确保在 _ViewImports.cshtml中放置 使用声明 @addTagHelper

@using YourNameSpace.Helpers
@addTagHelper *, YourNameSpace

注意

我使用Humanizer仅限英语的NuGet包 - Humanizer.Core。它比编写我自己的方法更强大。如果你不喜欢开销,你可以使用正则表达式。

答案 2 :(得分:1)

如何使用自定义属性并覆盖DisplayNameAttribute

 public class DisplayWithSpace : DisplayNameAttribute
    {
        public DisplayWithSpace([System.Runtime.CompilerServices.CallerMemberName]  string memberName ="")
        {

            Regex r = new Regex(@"(?!^)(?=[A-Z])");
            DisplayNameValue = r.Replace(memberName, " ");
        }
    }

,您的财产将是

[DisplayWithSpace]

public string FatherName { get; set; }