I have the following model:
class User
{
[Display(Name = "Display Name")]
public string Name { get; set; }
}
In standard Razor I would do something like the following to get the "Display Name":
<label asp-for="Model.Name"></label>
but that doesn't seem to work in Blazor. Does anyone know how to get the display name in a Blazor page without using reflection?
My implementation is to replace the Html.DisplayNameFor()
method from regular Razor;
@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 ?? "";
}
}
with this at the call site, either:
<DisplayName For="@(() => object.Member)" />
or
<DisplayName For="@(() => object.Member)">
<InputText @bind-Value="object.Member" />
</DisplayName>
Edit: to clarify, the two versions produce slightly different markup. The first would produce:
<label>Generated DisplayName</label>
And the second would produce
<label>
Generated DisplayName
<input value="WhateverTheValueIs" />
</label>
Additionally, in my implementation I added a bool
property to allow just plaintext output - since it turned out there was lots of times I just wanted the display name text out.
@BlackFenix2 I'm not allowed to comment (yet 😉) but <Label For="@(() => Model.Name))" />
should be <Label For="@(() => Model.Name)" />
One ')' to many
And to enhance your solution somewhat I've added @attributes="AdditionalAttributes"
so you can do this (for example) <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 ?? "";
}
}
At this time (preview7), they are not an out of the box feature to do it.
It's very easy to create your own custom label component (using a bit reflection of course) and encapsulate functionality in it:
@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 ?? "";
}
}
And use it in your .razor page:
<CustomLabel TItem="User" aspfor="@nameof(User.Name)"></CustomLabel>
Be free to improve it with Expressions
or more typed code (as @issac explains in their answer) and come back to us to explain your experience.
Try it at blazorfiddle.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With