Doug
Doug

Reputation: 15513

Html.DisplayFor with Generic Class

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?

Upvotes: 4

Views: 2813

Answers (1)

ataravati
ataravati

Reputation: 9155

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);      
}

Upvotes: 6

Related Questions