Как отобразить атрибут 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 63

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 заменяет v3 help-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 &lt;span&gt; elements with an <c>asp-description-for</c> attribute.
/// Adds an <c>id</c> attribute and sets the content of the &lt;span&gt; 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 &lt;label&gt; elements with an <c>asp-for</c> attribute.
/// Adds a <c>title</c> attribute to the &lt;label&gt; 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," "," "," ")