我有以下模型:
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 ?? "";
}
}
对不起,但在我看来,现在这是不可能的。我可能弄错了,这可能很容易设置。我对这个问题很感兴趣,我会把它发布在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