Search code examples
c#asp.net-mvc-3razorlambdadisplay-templates

ASP.NET MVC 3 Razor DisplayFor Delegate


I'm getting this error:

Templates can be used only with field access, property access, single-dimension array index, or single-parameter custom indexer expressions.

Here's my code (custom HTML helper, wrapping DisplayFor so i can choose a template):

public static string DisplayLocationTypeFor<TModel>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, LocationType>> expression, bool plural = false)
{
   return plural ? 
      htmlHelper.DisplayFor(expression, "LocationTypePlural").ToHtmlString() :
      htmlHelper.DisplayFor(expression).ToHtmlString();
}

When i use it like this, it works:

@Html.DisplayLocationTypeFor(model => model.LocationType)

Because the model has a property for LocationType.

But when i do this in another custom HTML helper:

public static MvcHtmlString SearchPreferenceButtonForModel<TModel>(this HtmlHelper<TModel> htmlHelper)
{
   // .. other code
   foreach (var property in htmlHelper.ViewData.ModelMetadata.Properties)
   {
      if (property.PropertyName == "LocationType")
         htmlHelper.DisplayLocationTypeFor(model => ((LocationType)Enum.ToObject(typeof(LocationType), property.Model)), true);
   } 
}

It errors.

I can change my DisplayLocationTypeFor helper to use htmlHelper.Display instead, but i'm not sure how.

Any ideas?

What i'm trying to do, is that i have a specific way of rendering out the LocationType model, that i want to happen across the site. Internally, the template uses a resource file, and some other smarts based on the URL. In other words, there is logic - which i don't wanted repeated.

This way, all my views/templates call into this template as a standard way of rendering the LocationType.


Solution

  • You need to read the error message:

    Templates can be used only with field access, property access, single-dimension array index, or single-parameter custom indexer expressions.

    It's telling you that only certain types of (very simple!) lambda expressions are permitted in a Razor template. If you have something more complex, you need to compute the value before you try to pass it to the template. Something like this should work:

    if (property.PropertyName == "LocationType") {
      LocationType locationType = (LocationType) Enum.ToObject(typeof(LocationType), property.Model));
      htmlHelper.DisplayLocationTypeFor(model => locationType, true);
    }