Friday, May 13, 2011

Sharing Razor Functions Across Views

Scott Guthrie wrote recently about using the @helper syntax within Razor, part of which was how to share these helpers across views.  I had a couple of functions defined in my Razor views that were repeated in various views and wondered if I could get this to work as well.  Turns out that it’s dead simple to do.
First, add an App_Code folder to your project (ok I know this seems like a throw-back, don’t blame me).  Next create a partial view named Razor.cshtml (or something else) in the App_Code folder.  Put your function into this folder as a static method.
@using System.Web.Mvc;

@functions
{
      public static  MvcHtmlString Checked<T>( IEnumerable<T> collection, T item)
      {
          if (collection != null && collection.Contains( item ))
          {
              return new MvcHtmlString( "checked=\"checked\"" );
          }
          return new MvcHtmlString( string.Empty );
      }  
}
Compile your solution, then open the view where you want to use the function. Add the code, using the name of the view as the class for the method
<div class="editor-label">
    @Html.LabelFor( model => model.RoleID )
</div>
<div class="editor-field">
    @foreach (var role in Model.AvailableRoles)
    {
        <div class="role-selections">
            <label>
                 <input type="checkbox"
                             name="RoleID"
                             value="@role.ID"
                             @Razor.Checked(Model.RoleID,role.ID) />
                 @role.Name.MakeTitle()
            </label>
        </div> 
    }
    <div>
    @Html.ValidationMessageFor( model => model.RoleID )
    </div>
</div>

It's important to make sure you open the view after the solution has been compiled or the new class might not be visible. Note, in the process of developing this particular example I realized that this code could easily be made into an HtmlHelper and I've since refactored to that, but it's still a good technique for making common Razor functions available across views.