I\'m trying to make a custom template for a basket item list. I need a few different templates, as I have different ways of displaying the item, depending on if it\'s on the web
I liked Dan's answer but just adjusted slightly as it can work for any IEnumerable:
using System.Collections;
using System.Text;
using System.Web.Mvc;
using System.Web.Mvc.Html;
namespace YourProject.Whatever
{
public static class DisplayExtensions
{
public static MvcHtmlString DisplayForIEnumerable<TModel>(this HtmlHelper<TModel> html, IEnumerable model, string templateName)
{
var tempResult = new StringBuilder();
foreach (var item in model)
{
var item1 = item;
tempResult.Append(html.DisplayFor(m => item1, templateName));
}
return MvcHtmlString.Create(tempResult.ToString());
}
}
}
And of course:
@Html.DisplayForIEnumerable(Model.Organizations, "NameOfYourDisplayTemplate")
Unfortunately that's a limitation of templated helpers. If you specify a template name for a collection property the template no longer applies automatically for each item of the collection. Possible workaround:
@for (int i = 0; i < Model.Items.Length; i++)
{
@Html.DisplayFor(x => x.Items[i], "CustomerItemBaseList")
}
I suggest another solution useful even more with lists of heterogeneous objects (i.e. BasketItem subclasses), using the additionalViewData parameter of the DisplayFor
method, like:
@DisplayFor(b=>b.Items, new { layout="row" })
in this way the helper works fine with IEnumerable<T>
, calling for each item (subclass of T) the relative DisplayTemplate, passing it the additionalViewData values in the ViewData
dictionary.
The template could so output different code for different layout values.
In the example above the template named View\Shared\DisplayTemplates\BasketItem (or the name of the subclass) should be like this:
@model MyProject.BasketItem // or BasketItem subclass
@{
string layout = ViewData["layout"] as string ?? "default";
switch(layout)
{
case "row":
<div class="row">
...
</div>
break;
// other layouts
...
default: // strongly recommended a default case
<div class="default-view>
...
</div>
break;
}
}
It is strongly recommended to provide always a default code.
I hope this suggestion could help.
That's a good idea, Darin. I'm lazy though, so I'd like to take it one step further and make an actual helper that wraps this. I also took out the lambda expression to simplify it for my case, but you can easily add that functionality back in.
public static class DisplayTextListExtension
{
public static MvcHtmlString DisplayForList<TModel>(this HtmlHelper<TModel> html, IEnumerable<string> model, string templateName)
{
var tempResult = new StringBuilder();
foreach (var item in model)
{
tempResult.Append(html.DisplayFor(m => item, templateName));
}
return MvcHtmlString.Create(tempResult.ToString());
}
}
Then the actual usage looks like:
@Html.DisplayForList(Model.Organizations, "infoBtn")