2016-02-09 1 views
2

Je voudrais créer un HtmlHelper qui peut être utilisé sur les propriétés IEnumerable.Puis-je créer un HtmlHelper spécifiquement pour les propriétés IEnumerable?

L'objectif est de l'utiliser comme ceci:

@Html.DisplayForEnumerable(m => m.EnumerableItemsProperty, "ViewTemplateName"); 

Si possible, je voudrais utiliser la syntaxe m => m.Items lambda (par opposition à passer par Model.Items).

C'est mon meilleur effort jusqu'à présent. Mais je ne suis pas sûr comment obtenir la variable items à partir du paramètre d'expression.

Je suppose que je devrais utiliser quelque chose comme IEnumerable<TValue> comme le type de retour de l'expression, mais je suis assez nouveau pour les génériques et je ne sais pas comment implémenter cela.

public static MvcHtmlString DisplayForEnumerable<TModel>(this HtmlHelper<TModel> html, Expression<Func<TModel, IEnumerable>> expression, string templateName, object additonalViewData = null) 
{ 
    var sb = new StringBuilder(); 

    // how to get items variable? 

    foreach (var item in items) 
    { 
     var item1 = item; 
     sb.Append(html.DisplayFor(m => item1, templateName, additonalViewData)); 
    } 

    return MvcHtmlString.Create(sb.ToString()); 
} 

Mise à jour

Pour clarifier - je prends cette approche parce que je voudrais être en mesure de spécifier si des modèles differnt pour le même modèle. Et l'énumération DisplayFor() normale ne se produit pas si vous spécifiez un modèle particulier.

Je sais que je pourrais simplement énumérer manuellement, mais je préférerais utiliser cette méthode à moins que quelqu'un de plus averti ne le conseille autrement.

+0

MVC a déjà cela. C'est juste '@ Html.DisplayFor (m => m.EnumerableItemsProperty)' et vous créez un 'EditorTemplate' pour le type qui est utilisé dans votre collection. –

+0

Merci Stephen. Je voudrais pouvoir utiliser différents modèles si possible, et l'énumération automatique ne se produit pas si vous spécifiez un modèle particulier. Je sais que je pourrais juste énumérer manuellement, mais j'ai pris un plaisir à le faire de cette façon. Conseilleriez-vous contre cela? –

+0

Je ne sais pas ce que vous voulez dire. Si vous avez un modèle dit 'Person.cs' alors vous créez un' EditorTemplate' - '/ View/Shared/EditorTemplates/Person.cshtml' alors la méthode' DisplayFor() 'va générer le html correct pour chaque' Person' dans la collection. Si vous souhaitez des modèles différents associés à différents contrôleurs, vous pouvez les placer dans les dossiers '/ Views/yourControllerName/EditorTemplates' –

Répondre

1

aide dont vous aurez besoin d'être

public static MvcHtmlString DisplayForEnumerable<TModel, TProperty>(this HtmlHelper<TModel> helper, Expression<Func<TModel, TProperty>> expression, string templateName, object additionalViewData = null) 
{ 
    ModelMetadata metaData = ModelMetadata.FromLambdaExpression(expression, helper.ViewData); 
    IEnumerable collection = metaData.Model as IEnumerable; 
    if (collection == null) 
    { 
     return helper.DisplayFor(expression, templateName, additionalViewData); 
    } 
    StringBuilder html = new StringBuilder(); 
    foreach (var item in collection) 
    { 
     html.Append(helper.DisplayFor(m => item, templateName, additionalViewData).ToString()); 
    } 
    return MvcHtmlString.Create(html.ToString()); 
} 

Notez le code vous permet de passer soit un T ou IEnumerable<T> (bien que le nom de la méthode ne maintenant pas vraiment de sens). Si vous voulez limiter à seulement IEnumerable<T> vous pouvez jeter un InvalidCastException si collection == null

Notez que cette approche ne fonctionnera pas si vous vouliez générer des contrôles de formulaire pour une collection (par exemple une méthode EditorForEnumerable()) parce que les indexeurs de collecte REQUISE ne pas être ajouté aux attributs name de génération. Une meilleure approche est d'utiliser le haut-DisplayFor() et EditorFor() méthodes qui va générer le code HTML correct pour les T et IEnemerable<T>

En supposant que vous avez une classe Person.cs, créez une vue partielle en /Views/Shared/DisplayTemplates/Person.cshtml (notez le nom du fichier doit correspondre au nom de la classe) et dans la vue il suffit d'utiliser

@Html.DisplayFor(m => m.yourCollectionProperty) 

Vous pouvez également créer des affichages spécifiques et éditeur de modèles pour chaque contrôleur, par exemple /Views/yourControllerName/DisplayTemplates/Person.cshtml. Cela vous permet d'utiliser un modèle dans /Persons/Index et un autre modèle dans /Organisation/Details/1 qui pourrait afficher une liste de Person associée à un Organisation

Et enfin, si vous avez besoin de 2 modèles différents pour Person dans le même contrôleur, vous pouvez utiliser la vue modèles, par exemple class PersonVM et class AssociatedPersonVM et créer un EditorTemplate pour chaque

+0

C'est une réponse modèle, des tonnes d'informations - merci un million. –