4

I have a class like this with a generic type:

Document<T>

This class is part of a view model

public class MyViewModel
{
   public IEnumerable<Document<T>> Documents {get;set;}

}

I'd like to use DisplayFor to dispatch to the appropriate template in the view.cshtml

@model MyViewModel
foreach(var vm in Model.Documents)
{
   @Html.DisplayFor(vm)
}

But I don't know how to create templates in Shared/DisplayTemplates that have a name of the class, but the C# name omits the generic parameters:

 Document`1

But this is insufficent, as it doesn't identify the full type structure.

Is there a way to use DisplayFor with DisplayTemplates and Generic Types?

Doug
  • 14,387
  • 17
  • 74
  • 104
  • This might help http://stackoverflow.com/questions/10616042/mvc3-razor-editor-display-templates-and-generics – Claudio Redi Aug 06 '13 at 18:59
  • possible duplicate of [ASP.NET MVC 3 Generic DisplayTemplates](http://stackoverflow.com/questions/5286706/asp-net-mvc-3-generic-displaytemplates) – Kyle Trauberman Aug 06 '13 at 18:59
  • @Kyle - That question is asking something related, but slightly different - can I have one template for all generics of a type. I am trying to get one template for each type. – Doug Aug 06 '13 at 19:52
  • Possible duplicate of [ASP.NET MVC Display Template for Generic Type](https://stackoverflow.com/questions/4531928/asp-net-mvc-display-template-for-generic-type) – KyleMit Nov 02 '17 at 12:34

1 Answers1

6

You can do something like this:

@foreach(var vm in Model.Documents)
{
    Type type = vm.GetType().GetGenericArguments()[0];
    var templateName = "Document_" + type.Name;
    @Html.DisplayFor(model => vm, templateName)
}

And, then, your DisplayTemplates will be named like "Docuement_Entity1.cshtml", "Document_Entity2.cshtml",... where Entity1 and Entity2 are your generic argument types.

Alternatively, you can create a TemplateName property for the Document class, set it just like in the code above, and use it in your View like this:

@foreach(var vm in Model.Documents)
{
    @Html.DisplayFor(model => vm, vm.TemplateName)
}

UPDATE:

If you want to use an Html Helper, you can do something like this:

public static MvcHtmlString DisplayGenericFor<TModel, TValue>(this HtmlHelper<TModel> helper, Expression<Func<TModel, TValue>> expression)
{
    var modelType = helper.ViewData.Model.GetType();
    if (!modelType.IsGenericType)
        throw new ArgumentException();

    Type genericType = modelType.GetGenericArguments()[0];
    var templateName = modelType.Name.Split('`').First() + "_" + genericType.Name;
    return helper.DisplayFor<TModel, TValue>(expression, templateName);      
}
ataravati
  • 8,891
  • 9
  • 57
  • 89
  • This is interesting. This is a good solution but perhaps it could just be wrapped in a different HtmlHelper extension? Ie, Html.DisplayGenericFor(model => vm) – Doug Aug 06 '13 at 19:53
  • hi, how do you call it, pass a custom display template name? – aggie Feb 14 '16 at 06:13
  • @aggie, no, the whole point of creating the Html Helper is to avoid passing the template name. The Html Helper automatically creates the template name based on the property type. See the code inside the html helper. – ataravati Feb 15 '16 at 14:57