There are many situations where I want to quickly iterate through a bunch of items in a view, and I prefer using the
foreach
statement. But sometimes, I need to also know the current index. So I wrote an extension method to IEnumerable<T>
that accepts Razor syntax as an argument and calls that template for each item in the enumeration.public static class HaackHelpers { public static HelperResult Each<TItem>( this IEnumerable<TItem> items, Func<IndexedItem<TItem>, HelperResult> template) { return new HelperResult(writer => { int index = 0; foreach (var item in items) { var result = template(new IndexedItem<TItem>(index++, item)); result.WriteTo(writer); } }); } }
This method calls the template for each item in the
enumeration, but instead of passing in the item itself, we wrap it in a
new class,
IndexedItem<T>
.public class IndexedItem<TModel> { public IndexedItem(int index, TModel item) { Index = index; Item = item; } public int Index { get; private set; } public TModel Item { get; private set; } }
And here’s an example of its usage within a view.
Notice that we pass in Razor markup as an argument to the method which
gets called for each item. We have access to the direct item and the
current index.
@model IEnumerable<Question> <ol> @Model.Each(@<li>Item @item.Index of @(Model.Count() - 1): @item.Item.Title</li>) </ol>
If you want to try it out, I put the code in a package in my personal NuGet feed for my code samples. Just connect NuGet to http://nuget.haacked.com/nuget/ and
Install-Package RazorForEach
. The package installs this code as source files in App_Code.
UPDATE: I updated the code and package to be more efficient (4/16/2011).
taken without any change from here : http://haacked.com/archive/2011/04/14/a-better-razor-foreach-loop.aspx
taken without any change from here : http://haacked.com/archive/2011/04/14/a-better-razor-foreach-loop.aspx