Razor is a great way to create views with ASP.NET MVC. One feature I use quite often are custom helpers. Instead of duplicating the same few lines of markup I simply create a reusable helper to generate HTML.
For example, you could create a helper to do something simple like render out a series of values…
@helper tabs(params Tab[] tabs) {
<ul>
@foreach(var tab in tabs) {
<li><a href="@tab.Url" >@tab.Text</a></li>
}
</ul>
}
Then use the helper by providing the parameters it needs…
@tabs(
new Tab { Text = "Google.com", Url = "https://google.com" },
new Tab { Text = "Hugoware.net", Url = "https://hugoware.net" },
new Tab { Text = "LosTechies.com", Url = "https://lostechies.com" })
This works pretty well for the most part but it is pretty limited in what it can do. Lets look at another approach.
Providing A ‘Template’
In the previous example values were passed into the helper and used to generate the markup required. This time, the helper accepts slightly different arguments that will allow a bit more control.
@helper dialog(string title,
Func<object, object> content) {
<div class="dialog-box" >
<h3>@title</h3>
<div class="dialog-box-content" >
@content(null)
</div>
</div>
}
This example uses a simple lambda (Func<object, object>) as an argument to provide markup to render. This allows the Razor block (@<text>…</text>) to be passed in as an argument for the helper.
@dialog("User Status",
@<strong>User is offline!</strong>
)
Now, the content is generated by an external source!
Using Types With Your Templates
So far the examples have used Func<object,object> as a template argument and then invoked the method with null as the argument. As it turns out, not only can you provide a value for that argument, if the argument type for the Func<…> is provided then it can be used from within a template.
@helper user_status(IEnumerable<User> users,
Func<User, object> online,
Func<User, object> offline) {
<div class="user-status-list" >
<div class="user-status" >
@foreach(var user in users) {
<h3>@user.Username</h3>
if (user.IsOnline) { @online(user); }
else { @offline(user); }
}
</div>
</div>
}
The helper above passes each User into the correct template. Now, a User can be referenced by using item from within the template.
@user_status(users,
online:@<div class="user-online" >
User @item.Username is online!
</div>,
offline: @<div class="user-offline" >
User @item.Username is offline!
<a href="#" >Send a message!</a>
</div>
)
Now, the contents of each template is unique to the User that was provided!