Как отобразить атрибут DisplayAttribute.Описание значение атрибута?
у меня есть класс модели, с таким свойством:
[Display(Name = "Phone", Description="Hello World!")]
public string Phone1 { get; set; }
отображение метки и рендеринга текстового поля для ввода в моем представлении довольно легко:
@Html.LabelFor(model => model.Organization.Phone1)
@Html.EditorFor(model => model.Organization.Phone1)
@Html.ValidationMessageFor(model => model.Organization.Phone1)
но как я могу отобразить значение атрибута аннотации описания, т. е. " Hello World!"??
12 ответов:
Я закончил с помощником вроде этого:
using System; using System.Linq.Expressions; using System.Web.Mvc; public static class MvcHtmlHelpers { public static MvcHtmlString DescriptionFor<TModel, TValue>(this HtmlHelper<TModel> self, Expression<Func<TModel, TValue>> expression) { var metadata = ModelMetadata.FromLambdaExpression(expression, self.ViewData); var description = metadata.Description; return MvcHtmlString.Create(string.Format(@"<span>{0}</span>", description)); } }
спасибо тем, кто привел меня в правильном направлении. :)
используя технику из этой статьи о том, как отображение визуальных подсказок для полей в форме, вы можете получить доступ к значению через следующее:
@Html.TextBoxFor( model => model.Email , new { title = ModelMetadata.FromLambdaExpression<RegisterModel , string>( model => model.Email , ViewData ).Description } )
Я собирался использовать принято отвечать, но это не сработало ASP.NET ядро 1/2 (a. k. a. MVC 6) потому что
ModelMetadata.FromLambdaExpression
больше не существует, и был перемещен вExpressionMetadataProvider
(также использование было немного изменено).это обновленный метод расширения, который вы можете использовать с ASP.NET ядро 1.1 & 2:
using System; using System.Linq.Expressions; using Microsoft.AspNetCore.Html; using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.AspNetCore.Mvc.ViewFeatures.Internal; public static class HtmlExtensions { public static IHtmlContent DescriptionFor<TModel, TValue>(this IHtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression) { if (html == null) throw new ArgumentNullException(nameof(html)); if (expression == null) throw new ArgumentNullException(nameof(expression)); var modelExplorer = ExpressionMetadataProvider.FromLambdaExpression(expression, html.ViewData, html.MetadataProvider); if (modelExplorer == null) throw new InvalidOperationException($"Failed to get model explorer for {ExpressionHelper.GetExpressionText(expression)}"); return new HtmlString(modelExplorer.Metadata.Description); } }
ASP.NET ядро 1
для ASP.NET ядро 1, тот же код работает, но вам понадобится другое пространство имен
usings
:using System; using System.Linq.Expressions; using Microsoft.AspNet.Html.Abstractions; using Microsoft.AspNet.Mvc.ViewFeatures;
использование
@Html.DescriptionFor(model => model.Phone1)
вам нужно будет написать пользовательский помощник, который будет отражать вашу модель, чтобы дать значение атрибута Description.
только при проверке (т. е. я не проверял это), но:
var attrib = (DisplayAttribute)Attribute.GetCustomAttribute( member, typeof(DisplayAttribute)); var desc = attrib == null ? "" : attrib.GetDescription()
@ViewData.ModelMetadata.Properties .Where(m => m.PropertyName == "Phone1").FirstOrDefault().Description
Итак, если вы использовали bootstrap, что-то вроде
<div class="form-group col-sm-6"> @Html.LabelFor(m => m.Organization.Phone1) @Html.EditorFor(m => m.Organization.Phone1) <p class="help-block"> @ViewData.ModelMetadata.Properties .Where(m => m.PropertyName == "DayCount").FirstOrDefault().Description </p> </div>
In ASP.NET MVC Core вы можете использовать новые помощники тегов, что делает ваш HTML похожим... HTML:)
такой:
<div class="form-group row"> <label asp-for="Name" class="col-md-2 form-control-label"></label> <div class="col-md-10"> <input asp-for="Name" class="form-control" aria-describedby="Name-description" /> <span asp-description-for="Name" class="form-text text-muted" /> <span asp-validation-for="Name" class="text-danger" /> </div> </div>
Примечание 1: Вы можете использовать
aria-describedby
атрибут в элементе ввода как этот идентификатор будет создан автоматически в элементе span с .примечание 2: в Bootstrap 4, классы
form-text
иtext-muted
заменяет v3help-block
класс для текста справки уровня блока.чтобы это волшебство произошло, вам просто нужно создать новый помощник тега:
using System; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.AspNetCore.Mvc.ViewFeatures; using Microsoft.AspNetCore.Razor.TagHelpers; /// <summary> /// <see cref="ITagHelper"/> implementation targeting <span> elements with an <c>asp-description-for</c> attribute. /// Adds an <c>id</c> attribute and sets the content of the <span> with the Description property from the model data annotation DisplayAttribute. /// </summary> [HtmlTargetElement("span", Attributes = DescriptionForAttributeName)] public class SpanDescriptionTagHelper : TagHelper { private const string DescriptionForAttributeName = "asp-description-for"; /// <summary> /// Creates a new <see cref="SpanDescriptionTagHelper"/>. /// </summary> /// <param name="generator">The <see cref="IHtmlGenerator"/>.</param> public SpanDescriptionTagHelper(IHtmlGenerator generator) { Generator = generator; } /// <inheritdoc /> public override int Order { get { return -1000; } } [HtmlAttributeNotBound] [ViewContext] public ViewContext ViewContext { get; set; } protected IHtmlGenerator Generator { get; } /// <summary> /// An expression to be evaluated against the current model. /// </summary> [HtmlAttributeName(DescriptionForAttributeName)] public ModelExpression DescriptionFor { get; set; } /// <inheritdoc /> /// <remarks>Does nothing if <see cref="DescriptionFor"/> is <c>null</c>.</remarks> public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (output == null) { throw new ArgumentNullException(nameof(output)); } var metadata = DescriptionFor.Metadata; if (metadata == null) { throw new InvalidOperationException(string.Format("No provided metadata ({0})", DescriptionForAttributeName)); } output.Attributes.SetAttribute("id", metadata.PropertyName + "-description"); if( !string.IsNullOrWhiteSpace( metadata.Description)) { output.Content.SetContent(metadata.Description); output.TagMode = TagMode.StartTagAndEndTag; } } }
и сделать ваши помощники тегов доступны для всех наших видов бритвы. Добавьте директиву addTagHelper в
Views/_ViewImports.cshtml
file:@addTagHelper "*, YourAssemblyName"
Примечание 1: Заменить
YourAssemblyName
С именем сборки вашего проекта.примечание 2: Вам просто нужно сделать это один раз, для всех ваших помощников тегов!
дополнительная информация о помощниках тегов здесь: https://docs.asp.net/en/latest/mvc/views/tag-helpers/intro.html
вот именно! Удачи с новыми помощниками тегов!
В дополнение к Якоб Гаде а отличный ответ:
Если вам нужно поддержать
DescriptionAttribute
вместоDisplayAttribute
,его отличным решением все еще работает, если мы переопределяем MetadataProvider:public class ExtendedModelMetadataProvider : DataAnnotationsModelMetadataProvider { protected override ModelMetadata CreateMetadata(IEnumerable<System.Attribute> attributes, Type containerType, Func<object> modelAccessor, Type modelType, string propertyName) { //Possible Multiple Enumerations on IEnumerable fix var attributeList = attributes as IList<System.Attribute> ?? attributes.ToList(); //Default behavior var data = base.CreateMetadata(attributeList, containerType, modelAccessor, modelType, propertyName); //Bind DescriptionAttribute var description = attributeList.SingleOrDefault(a => typeof(DescriptionAttribute) == a.GetType()); if (description != null) { data.Description = ((DescriptionAttribute)description).Description; } return data; } }
это нужно регистрировать в
Application_Start
методGlobal.asax.cs
:ModelMetadataProviders.Current = new ExtendedModelMetadataProvider();
...и если вы предпочитаете иметь описание в виде подсказки в метке формы, добавьте помощник тега следующим образом:
using System; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.AspNetCore.Mvc.ViewFeatures; using Microsoft.AspNetCore.Razor.TagHelpers; /// <summary> /// <see cref="ITagHelper"/> implementation targeting <label> elements with an <c>asp-for</c> attribute. /// Adds a <c>title</c> attribute to the <label> with the Description property from the model data annotation DisplayAttribute. /// </summary> [HtmlTargetElement("label", Attributes = ForAttributeName)] public class LabelTitleTagHelper : TagHelper { private const string ForAttributeName = "asp-for"; /// <summary> /// Creates a new <see cref="LabelTitleTagHelper"/>. /// </summary> /// <param name="generator">The <see cref="IHtmlGenerator"/>.</param> public LabelTitleTagHelper(IHtmlGenerator generator) { Generator = generator; } /// <inheritdoc /> public override int Order { get { return -1000; } } [HtmlAttributeNotBound] [ViewContext] public ViewContext ViewContext { get; set; } protected IHtmlGenerator Generator { get; } /// <summary> /// An expression to be evaluated against the current model. /// </summary> [HtmlAttributeName(ForAttributeName)] public ModelExpression TitleFor { get; set; } /// <inheritdoc /> /// <remarks>Does nothing if <see cref="TitleFor"/> is <c>null</c>.</remarks> public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (output == null) { throw new ArgumentNullException(nameof(output)); } var metadata = TitleFor.Metadata; if (metadata == null) { throw new InvalidOperationException(string.Format("No provided metadata ({0})", ForAttributeName)); } if (!string.IsNullOrWhiteSpace(metadata.Description)) output.Attributes.SetAttribute("title", metadata.Description); } }
что создаст новый с
Description
свойство из аннотации данных моделиDisplayAttribute
.красивая часть заключается в том, что вам не нужно прикасаться к вашим сгенерированным видам лесов! Потому что этот помощник тега нацелен на на
label
элемент, который уже есть!
если кому-то интересно, как использовать принято отвечать
1 - в обозревателе решений > добавить новую папку, назовите ее"помощники", например
2-Добавить новый класс, назовите его "CustomHtmlHelpers" например
3 - вставьте код :public static class MvcHtmlHelpers { public static string DescriptionFor<TModel, TValue>(this HtmlHelper<TModel> self, Expression<Func<TModel, TValue>> expression) { var metadata = ModelMetadata.FromLambdaExpression(expression, self.ViewData); var description = metadata.Description; return string.IsNullOrWhiteSpace(description) ? "" : description; } }
4-в вашей модели или viewModel, используя его это:
[Display(Name = "User Name", Description = "Enter your User Name")] public string FullName { get; set; }
5-в вашем представлении бритвы, после @model, введите эту строку
@using YOUR_PROJECT.Helpers
6 - дисплей описание выглядит так:
@Html.DescriptionFor(m => m.FullName)
7-Вы можете использовать описание для отображения текста в заполнителе ввода:
@Html.DisplayNameFor(m => m.FullName) @Html.TextBoxFor(m => m.FullName, new { @class = "form-control", placeholder = Html.DescriptionFor(m => m.FullName) })
спасибо
ответ HANDL, обновлен для ASP.NET ядро 2.0
using System; using System.Linq.Expressions; using Microsoft.AspNetCore.Html; using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.AspNetCore.Mvc.ViewFeatures.Internal; public static class HtmlExtensions { public static IHtmlContent DescriptionFor<TModel, TValue>(this IHtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression) { if (html == null) throw new ArgumentNullException(nameof(html)); if (expression == null) throw new ArgumentNullException(nameof(expression)); var modelExplorer = ExpressionMetadataProvider.FromLambdaExpression(expression, html.ViewData, html.MetadataProvider); if (modelExplorer == null) throw new InvalidOperationException($"Failed to get model explorer for {ExpressionHelper.GetExpressionText(expression)}"); return new HtmlString(modelExplorer.Metadata.Description); } }
вы всегда можете создать свой собственный расширение, как это:
public static MvcHtmlString ToolTipLabel (string resourceKey, string text, bool isRequired, string labelFor = "", string labelId = "",string className="") { string tooltip = string.Empty; StringBuilder sb = new StringBuilder(); if (!string.IsNullOrEmpty(resourceKey)) { var resources = GetAllResourceValues(); if (resources.ContainsKey(resourceKey)) { tooltip = resources[resourceKey].Value; } } sb.Append("<label"); if (!string.IsNullOrEmpty(labelFor)) { sb.AppendFormat(" for=\"{0}\"", labelFor); } if (!string.IsNullOrEmpty(labelId)) { sb.AppendFormat(" Id=\"{0}\"", labelId); } if (!string.IsNullOrEmpty(className)) { sb.AppendFormat(" class=\"{0}\"", className); } if (!string.IsNullOrEmpty(tooltip)) { sb.AppendFormat(" data-toggle='tooltip' data-placement='auto left' title=\"{0}\"",tooltip); } if (isRequired) { sb.AppendFormat("><em class='required'>*</em> {0} </label></br>", text); } else { sb.AppendFormat(">{0}</label></br>", text); } return MvcHtmlString.Create(sb.ToString()); }
и может получить его в такой вид:
@HtmlExtension.ToolTipLabel(" "," ",true," "," "," ")