HtmlHelper in ASP.NET MVC3 that uses Action<T> as template: Razor syntax?
Let me preface this by saying that perhaps there's a better way to do this, and Razor is lighting the way. In any case, I have an HTML he开发者_高级运维lper that acts as a repeater of sorts, but after an arbitrary number of repeats, it inserts an alternate template. Most obvious use? Tables that start a new row after x cells. The helper looks like this:
public static void SeriesSplitter<T>(this System.Web.Mvc.HtmlHelper htmlHelper, IEnumerable<T> items, int itemsBeforeSplit, Action<T> template, Action seriesSplitter)
{
if (items == null)
return;
var i = 0;
foreach (var item in items)
{
if (i != 0 && i % itemsBeforeSplit == 0)
seriesSplitter();
template(item);
i++;
}
}
And in a Webforms view, the usage looks like this:
<table>
<tr>
<% Html.SeriesSplitter(Model.Photos, 4, photo => { %>
<td><img src="<%=ResolveUrl("~/Thumbnail.ashx?id=" + photo.ID)%>" alt="<%=Html.Encode(photo.Title)%>" /></td>
<% }, () => { %></tr><tr><% }); %>
</tr>
</table>
In this case, you'd have a table that renders four cells, then starts a new row by using the alternate template (the row start and end tags). The problem is that I can't find a way to make this work in Razor. Using a lambda inside of a Razor view seems like a pretty weird construct.
What would you do?
Phil actually had a good post that solves the problem here:
http://haacked.com/archive/2011/02/27/templated-razor-delegates.aspx
This is a job for Func<object, HelperResult>
(though I'm doing this from memory so it might need tweaking):
public static void SeriesSplitter<T>(this System.Web.Mvc.HtmlHelper htmlHelper,
IEnumerable<T> items,
int itemsBeforeSplit,
Func<object, HelperResult> template,
Func<object, HelperResult> seriesSplitter) {
//pretty much same code here as before
}
Then you would call it like so
@Html.SeriesSplitter(Model.Items, 3, @<td>item.Id</td>, @:</td><td>
)
Just note that because of how Razor does tag balancing during parsing you need the new line after @:</td><td>
精彩评论