web-dev-qa-db-fra.com

@ Html.DisplayNameFor pour plus de détails modèle

Dans mon modèle, j'ai une entité

public class Carrier
{
public Guid CarrierId { get; set; }
public string Name { get; set; }
}

J'ai aussi un ViewModel

public class CarrierIndexViewModel
{
public IEnumerable<Carrier> Carriers { get; set; }
public PagingInfo PagingInfo { get; set; }
}

J'ai une vue d'index fortement typée (CarrierIndexViewModel), qui est supposée afficher une table de Carrier à l'aide de PagingInfo.

J'essaie d'utiliser l'aide HTML pour afficher Carrier.Name dans l'en-tête de ma table Lorsque j'ai utilisé IEnumerable comme modèle pour cette vue, j'avais @Html.DisplayFor(model => model.Name)

Comment puis-je obtenir le même résultat en utilisant mon nouveau CarrierIndexViewModel pour afficher le titre de Carrier.Name?

25
Alex

Vous pouvez ajouter une instruction @using à votre vue pour spécifier le type de transporteur, puis vous devrez parcourir la propriété Carriers de votre modèle.

Votre vue ressemblera à quelque chose comme ..

@model CarrierIndexViewModel
@using Carrier

@foreach(Carrier c in Model.Carriers)
{
 @Html.DisplayFor(model => c.Name)
}
8
Jed

J'ai trouvé qu'il n'y avait pas besoin de méthodes d'assistance, de code supplémentaire ou de boucle dans la collection. Je viens d'utiliser les éléments suivants:

@Html.DisplayNameFor(model => model.Carriers.FirstOrDefault().Name)

Cela fonctionne toujours même si FirstOrDefault() retournerait null car il ne recherche que des métadonnées, la propriété Name elle-même n'est pas accessible.

Un grand merci à @ Kurian qui a inspiré cette réponse.

39
Red Taz

J'ai un problème similaire, car je ne veux pas taper mes noms de colonne à la main, j'ai donc écrit un assistant:

public static IHtmlString DisplayColumnNameFor<TModel, TClass, TProperty>
    (this HtmlHelper<TModel> helper, IEnumerable<TClass> model,
    Expression<Func<TClass, TProperty>> expression)
{ 
    var name = ExpressionHelper.GetExpressionText(expression);
    name = helper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(name);
    var metadata = ModelMetadataProviders.Current.GetMetadataForProperty(
        () => Activator.CreateInstance<TClass>(), typeof(TClass), name);

    return new MvcHtmlString(metadata.DisplayName);
}

Ensuite, dans la vue, vous l'appellerez

@Html.DisplayColumnNameFor(Model.Carriers, m => m.Name)

Veuillez noter que vous pouvez utiliser l'attribut Display qui accepte le nom et de nombreuses autres personnalisations comme le fichier de ressources, etc.

public class Carrier
{
  [Display(Name="Carrier ID")]
  public Guid CarrierId { get; set; }
  [Display(Name="Carrier Name")]
  public string Name { get; set; }
}
17
Matija Grcic

Voici une approche basée sur la méthode d'extension originalDisplayNameFor et fonctionne de manière cohérente.

Une méthode d'extension pour HtmlHelper:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Web;
using System.Web.Mvc;

public static class HtmlHelperExtensions
{
    public static MvcHtmlString DisplayNameFor<TModel, TEnumerable, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, IEnumerable<TEnumerable>>> enumerableExpression, Expression<Func<TEnumerable, TValue>> valueExpression)
    {
        var metadata = ModelMetadata.FromLambdaExpression(valueExpression, new ViewDataDictionary<TEnumerable>());
        string displayName = metadata.DisplayName ?? metadata.PropertyName ?? ExpressionHelper.GetExpressionText(valueExpression).Split('.').Last();
        return new MvcHtmlString(HttpUtility.HtmlEncode(displayName));
    }
}

Et voilà comment il pourrait être utilisé dans une vue:

@Html.DisplayNameFor(m => m.Carriers, c => c.Name)
4
Deilan

J'avais une exigence similaire, mais j'avais besoin d'obtenir des noms d'affichage pour les propriétés d'une autre classe non énumérable afin que la solution de @plurby n'ait pas fonctionné. J'ai fini par résoudre ce problème en créant un appel fluide qui peut être utilisé pour obtenir un nouveau HtmlHelper pour tout type arbitraire. Le code de l'extension et de l'adaptateur est:

public static class HtmlHelpers
{
    public static HtmlHelperAdapter<TModel> Adapt<TModel>(this HtmlHelper<TModel> helper)
    {
        return new HtmlHelperAdapter<TModel>(helper);
    }

    public class HtmlHelperAdapter<TModel>
    {
        private readonly HtmlHelper<TModel> _helper;

        public HtmlHelperAdapter(HtmlHelper<TModel> helper)
        {
            _helper = helper;
        }

        public HtmlHelper<TNewModel> For<TNewModel>()
        {
            return new HtmlHelper<TNewModel>(_helper.ViewContext, new ViewPage(), _helper.RouteCollection);
        }
    }
}

Vous pouvez ensuite l'utiliser dans la vue comme ceci:

<td>@(Html.Adapt().For<MyOtherModel>().DisplayNameFor(m => m.SomeProperty))</td>

L'un des avantages est que cette approche fonctionnera pour n'importe quelle extension HtmlHelper, pas seulement DisplayNameFor (mais gardez à l'esprit que le HtmlHelper adapté n'a pas de données de vue car tout est typé en fonction du modèle utilisé dans le et ne fonctionnera donc pas dans le HtmlHelper adapté).

3
daveaglick