如何将"Display Name"放在 Blazor 页面上的标签中?



我有以下模型:

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

在标准 Razor 中,我会执行以下操作来获取"显示名称":

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

但这似乎在 Blazor 中不起作用。有谁知道如何在不使用反射的情况下在 Blazor 页面中获取显示名称?

我的实现是替换常规 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 属性以仅允许纯文本输出 - 因为事实证明,很多时候我只想显示名称文本。

> @BlackFenix2 我不允许发表评论(还😉(,但<Label For="@(() => Model.Name))" />应该<Label For="@(() => Model.Name)" /> 一个"("到许多

为了在一定程度上增强您的解决方案,我添加了@attributes="AdditionalAttributes"以便您可以执行此操作(例如(<Label class="col-3 col-form-label" For="@(() => Model.Name)" />

@using System.Reflection
@using System.ComponentModel
@using System.Linq.Expressions;
<label @attributes="AdditionalAttributes">@label</label>
@code {
    [Parameter] public Expression<Func<string>> For { get; set; }
    [Parameter(CaptureUnmatchedValues = true)]
    public IDictionary<string, object> AdditionalAttributes { 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 ?? "";
    }
}

坏消息:

目前(预览版 7(,它们不是开箱即用的功能。

好消息:

创建自己的自定义标签组件(当然使用位反射(并将功能封装在其中非常容易:

@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 试试吧。

我将解决方案从@Kruft扩展到能够使用元数据类型属性并使用 ResX 管理器维护资源文件中的显示名称。为了简短起见,我只提供了代码片段:

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

奖励:在大型项目中,可以将资源文件i放在一个公共项目中。

玩得愉快!

我对此

进行了即兴发挥,我找到了一种方法来获取传入表达式的属性的显示名称,如@Issac所说的。 此实现将适用于附加到属性的任何自定义属性。

并感谢@dani埃雷拉的初始代码

 <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 ?? "";
    }
}
@user3224222,

对不起,但在我看来,现在这是不可能的。我可能弄错了,这可能很容易设置。我对这个问题很感兴趣,我会把它发布在github上,看看它是如何做到的。但是,您可以创建具有嵌入式标签元素的组件,以解决您的问题。您的组件应类似于内置的验证消息 (https://github.com/aspnet/AspNetCore/blob/4928eb3de0d80570dad93a143b52a8f5a205dac7/src/Components/Web/src/Forms/ValidationMessage.cs(,其中包含一个名为 For 的属性,该属性可以解决问题。验证消息的设置方式如下:

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

您的组件也可以进行类似的设置:

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

注意:您可以按原样复制验证消息类的代码并删除所有不相关的代码...您需要 For 属性和组件的呈现(重写 BuildRenderTree(

祝你好运。

在共享文件夹中创建一个名为 : 自定义标签的组件。

使用以下代码:https://blazorfiddle.com/s/960ciouw

相关内容

  • 没有找到相关文章

最新更新