2

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.

RPM1984
  • 72,246
  • 58
  • 225
  • 350

2 Answers2

1

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);
} 
Peter Gluck
  • 8,168
  • 1
  • 38
  • 37
  • Thanks, that was it. BTW, know you prob didnt mean to - but you've come across as pretty brash. I did read the message, and i've received it several times in the past. I just didn't know how to resolve it in this particular scenario. Anyway, thanks for you help! – RPM1984 Aug 17 '12 at 05:58
  • You're welcome--glad I could help. Sorry, I didn't mean to be brash. – Peter Gluck Aug 17 '12 at 06:11
0

You can achieve that by composing a display template for LocationType model.

Here is an answer that says how to achieve that. In short:

  1. Create a folder ~/Views/Shared/DisplayTemplates.
  2. Create a view named LocationType in the new folder you created with model type LocationType. Whenever you try a @DisplayFor(model => model.LocationType), the view you created for LocationType will be rendered.
Community
  • 1
  • 1
Mohayemin
  • 3,841
  • 4
  • 25
  • 54
  • That's exactly what i'm doing, IN that actual helper. I'm building a bit of logic on top of that. Using your example: `htmlHelper.DisplayFor(model => ((LocationType)Enum.ToObject(typeof(LocationType), property.Model)), true)` still breaks with the same error. The error here is relating to the lambda expression passed to `DisplayFor`, it doesnt like it unless the model is strongly typed to that type. – RPM1984 Aug 17 '12 at 04:36
  • @RPM1984: I am sorry I misinterpreted your question. – Mohayemin Aug 17 '12 at 16:11