ASP .Net Core Custom Tag Helper to Convert CamelCase Properties to spaces

半世苍凉 提交于 2019-12-03 15:16:44

You can achieve this by building and registering a custom display metadata provider. There are libraries that will perform more elaborate "humanization" to the property names, but you can achieve something pretty useful with some trusty regular expressions.

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

The IsTransformRequired method ensures that you can still override the provider with a decorated property when you need to.

Register the provider on startup through the AddMvcOptions method on IMvcBuilder:

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

If you only care about label, you can easily override 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);
    }
}

Usage

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

Please ensure to place using statement and @addTagHelper inside _ViewImports.cshtml.

@using YourNameSpace.Helpers
@addTagHelper *, YourNameSpace

Note

I use Humanizer English Only NuGet Package - Humanizer.Core. It is more robust than writing my own method. If you doesn't like overhead, you can just use Regular Expression.

how about using a custom attribute and overriding DisplayNameAttribute

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

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

and your property will be

[DisplayWithSpace]

public string FatherName { get; set; }
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!