如何在Blazor剃须刀页面的标签上获得“显示名称”?

时间:2019-07-25 12:47:26

标签: c# razor blazor

我有以下模型:

class User
{
    [Display(Name = "Display Name")]
    public string Name { get; set; }
}

在标准Razor中,我会做类似的事情以获取“显示名称”

<label asp-for="Model.Name"></label>

但是在Blazor中似乎不起作用。有人知道如何在Blazor页面中获得显示名称而不使用反射吗?

6 个答案:

答案 0 :(得分:5)

@ BlackFenix2我尚未发表评论(但?),但是SKPaint应该是<Label For="@(() => Model.Name))" /> 一个')'众多

为增强您的解决方案,我添加了<Label For="@(() => Model.Name)" />,因此您可以执行此操作(例如 @attributes="AdditionalAttributes"

<Label class="col-3 col-form-label" For="@(() => Model.Name)" />

答案 1 :(得分:4)

我的实现是替换常规Razor中的Html.DisplayNameFor()方法;

@using System.Reflection
@using System.Linq.Expressions;
@using System.ComponentModel.DataAnnotations;
@typeparam T
@if (ChildContent == null)
{
    <label>@label</label>
}
else
{
    <label>
        @label
        @ChildContent
    </label>
}
@code {
    [Parameter] public Expression<Func<T>> For { get; set; }
    [Parameter] public RenderFragment ChildContent { get; set; }

    private string label => GetDisplayName();

    private string GetDisplayName()
    {
        var expression = (MemberExpression)For.Body;
        var value = expression.Member.GetCustomAttribute(typeof(DisplayAttribute)) as DisplayAttribute;
        return value?.Name ?? expression.Member.Name ?? "";
    }
}

在呼叫站点上使用以下方法之一:

<DisplayName For="@(() => object.Member)" />

<DisplayName For="@(() => object.Member)">
    <InputText @bind-Value="object.Member" />
</DisplayName>

编辑:为澄清起见,两个版本的标记略有不同。第一个会产生:

<label>Generated DisplayName</label>

第二个会产生

<label>
    Generated DisplayName
    <input value="WhateverTheValueIs" />
</label>

另外,在我的实现中,我添加了一个bool属性,仅允许以纯文本格式输出-因为事实证明,很多时候我只是想把显示名称文本输出。

答案 2 :(得分:2)

坏消息:

这一次(preview7),它们并不是开箱即用的功能。

好消息:

创建您自己的自定义标签组件(当然需要一点点反射)并在其中封装功能非常容易:

@using System.Linq
@using System.Reflection
@using System.ComponentModel.DataAnnotations

@typeparam TItem

<label for="@fortag">@label</label>

@code {
    [Parameter] public string aspfor { get; set; }        

    private string label => GetDisplayName(aspfor);

    private string fortag => aspfor;

    private string GetDisplayName(string propertyname)
    {
        MemberInfo myprop = typeof(TItem).GetProperty(propertyname) as MemberInfo;
        var dd = myprop.GetCustomAttribute(typeof(DisplayAttribute)) as DisplayAttribute;
        return dd?.Name ?? "";
    }

}

并在您的.razor页面中使用它:

<CustomLabel TItem="User" aspfor="@nameof(User.Name)"></CustomLabel>

可以随意使用Expressions或更多类型的代码(如@issac在他们的回答中解释的)来进行改进,然后请我们来解释您的经验。

演示:

blazorfiddle尝试一下。

答案 3 :(得分:1)

@ user3224222,对不起,但是在我看来,这目前无法实现。我可能会误会,这可能很容易设置。这个问题让我很感兴趣,我将其发布在github中以了解如何实现。但是,您可以创建带有嵌入式标签元素的组件来解决您的问题。您的组件应该与内置的ValidationMessage(https://github.com/aspnet/AspNetCore/blob/4928eb3de0d80570dad93a143b52a8f5a205dac7/src/Components/Web/src/Forms/ValidationMessage.cs)相似,并具有一个名为 For 的属性,该属性可以解决问题。设置ValidationMessage的方法如下:

<ValidationMessage For="@(() => starship.MaximumAccommodation)" />

您的组件可以类似地设置:

<LabelText For="@(() => Model.Name))" />

注意:您可以按原样复制ValidationMessage类的代码并删除所有不相关的代码...您需要For属性和组件的呈现(覆盖BuildRenderTree)

祝你好运。

答案 4 :(得分:1)

我从@Kruft扩展了解决方案,使其能够使用MetadataType属性,并使用ResX Manager来维护资源文件中的显示名称。为了简短起见,我只提供了代码片段:

    [MetadataType(typeof(AnforderungDtoMetadata))]
    public partial class AnforderungDto : IMapBaseFrom<Anforderung>
    {

        public Guid Id { get; set; }
        public short ReychsNr { get; set; }
        public int SassenNr { get; set; }
        public string AbgerufenVonName { get; set; }
    }
    public class AnforderungDtoMetadata
    {
       [Display(Name = nameof(Resources.AnforderungId), ResourceType = typeof(Resources))]
       public object Id { get; set; } 
       [Display(Name = nameof(Resources.ReychsNr), ResourceType = typeof(Resources))]
       public object ReychsNr { get; set; }
    }

Blazor代码相同,我只扩展了Methode来获得显示名称:

using Microsoft.AspNetCore.Components;
using System.Linq.Expressions;
using System.ComponentModel.DataAnnotations;
using System.Reflection;
using System;
using System.Linq;
using System.Resources;
using System.Globalization;

namespace avsweb.Components
{
    public partial class DisplayName<T> : ComponentBase
    {
        [Parameter] public Expression<Func<T>> For { get; set; }
        [Parameter] public RenderFragment ChildContent { get; set; }

        private string label => GetDisplayName();

        private string GetDisplayName()
        {
            var expression = (MemberExpression)For.Body;
            var value = expression.Member.GetCustomAttribute(typeof(DisplayAttribute), true) as DisplayAttribute;
            if (value == null)
            {
                var metaData = expression.Member.DeclaringType.GetCustomAttribute(typeof(MetadataTypeAttribute), true) as MetadataTypeAttribute;
                if (metaData != null)
                {
                    var mdProp = metaData.MetadataClassType.GetProperties()
                             .ToList()
                             .Where(p => p.Name == expression.Member.Name)
                             .FirstOrDefault();
                    if (mdProp != null)
                    {
                        var mPropAttr = mdProp.GetCustomAttribute(typeof(DisplayAttribute)) as DisplayAttribute;
                        if (mPropAttr != null)
                        {
                            if (mPropAttr.ResourceType!=null)
                            {
                                return GetDisplayNameFromResource(mPropAttr);
                            }
                            //return mPropAttr.Name;
                        }
                    }
                }

            }
            if (value.ResourceType!=null)
            {
                return GetDisplayNameFromResource(value);
            }
            return value?.Name ?? expression.Member.Name ?? "";
        }

        private static string GetDisplayNameFromResource(DisplayAttribute mPropAttr)
        {
            ResourceManager rm = new ResourceManager(mPropAttr.ResourceType);
            var dispName = rm.GetString(mPropAttr.Name, CultureInfo.CurrentCulture);
            return dispName;
        }

奖金:在大型项目中,可以将资源文件放在一个普通项目中。

玩得开心!

答案 5 :(得分:0)

对此我轻描淡写,我找到了一种方法来获取传递@Issac表示的表达式的属性的显示名称。此实现将与附加到该属性的任何自定义属性一起使用。

感谢@dani herrera的初始代码

 <Label For="@(() => Model.Name))" />
@using System.Linq
@using System.Reflection
@using System.ComponentModel
@using System.Linq.Expressions;

<label>@label</label>

@code {


    [Parameter] public Expression<Func<string>> For { get; set; }

    private string label => GetDisplayName();

    private string GetDisplayName()
    {
        var expression = (MemberExpression)For.Body;
        var value = expression.Member.GetCustomAttribute(typeof(DisplayNameAttribute)) as DisplayNameAttribute;
        return value?.DisplayName ?? expression.Member.Name ?? "";
    }

}