ASP.NET MVC 3 Razor DisplayFor Delegate
Asked Answered
M

2

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.

Monkfish answered 17/8, 2012 at 1:5 Comment(2)
what are you trying to do actually? Can you tell us the context? May be there are other solutions to achieve that.Thibault
@Thibault - edited with reasoning.Monkfish
W
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);
} 
Womanhater answered 17/8, 2012 at 5:43 Comment(2)
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!Monkfish
You're welcome--glad I could help. Sorry, I didn't mean to be brash.Womanhater
T
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.
Thibault answered 17/8, 2012 at 4:6 Comment(2)
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.Monkfish
@RPM1984: I am sorry I misinterpreted your question.Thibault

© 2022 - 2024 — McMap. All rights reserved.