Framework Madness!

And other adventures C# and asp.net …

Asp.net MVC 2 – Of(T).Item for Html.DisplayFor

with one comment

Sometimes the easiest solutions are not always obvious. Take for example  if you try to call against the indexer of a list when calling ‘Html.DisplayFor’ such as:

   1: <%
   1: for (int i = 0; i < Model.Elements.Count; i++){

%>

   2:       <%
   1: =Html.DisplayFor(m => m.Elements[i])  

%>

   3: <%
   1: }

%>

You get the following error:

System.InvalidOperationException: Templates can be used only with field and property accessor expressions.

 

Well – that sucks. And so I went and made workarounds such as DisplayItemFor, and yet found it wanting. And I explored into the bowels of lambda expressions, and I wanted out.

And then it hit me. You can only return expressions that are for properties or fields. Okay – so let’s say I do something like call the indexer and then a property on the returned object:

   1: <%
   1: =Html.DisplayFor(m => m.Elements[i].Title)  

%>

Okay – that actually works because we end with a property expression. But what if you use a foreach loop instead. Here is the ‘Html.DisplayFor’ call:

   1: <%
   1: =Html.DisplayFor(m => m.Elements[m.Elements.IndexOf(element)].Title)  

%>

And that works to … but who wants to write that? I don’t. And you still don’t have the capability of calling an object template for just the element after all of that work.

Okay – so what about using Linq? Actually, you can make that happen if you just remember to end with a field or property expression:

   1: <%
   1: =Html.DisplayFor(m => m.Elements.Where( e=> e == element ).Select( e=> new{item=e}).FirstOrDefault().item)  

%>

That actually works for the object template and the field and property templates out of the box. But who wants this much Linq fun when all you want is an element tied to an expression of the ViewModel? (I don’t).

So why not try an extension method – just make for any enumerable. It needs to be simple to call, and we need to get element back in the for ofm a callable property.

Here is an example for an object template would look like:

   1: <%
   1: =Html.DisplayFor(m => m.Elements.Of(element).Item)  

%>

Here is an example for a field or property template would look like:

   1: <%
   1: =Html.DisplayFor(m => m.Elements.Of(element).Item.Title)  

%>

And below is the code. It is simple and works. When you call the ‘Of’ extension method it does the following:

  • Verifies that the element passed in is in the enumerable (in this case m.Elements).
  • Returns a simple wrapper object that contains the element passed.
  • The element is returned by the wrapper property ‘Item’, making easy to get an object template.

Here’s the code:

   1: public class EnumerableItemOf<T>

   2: {

   3:     internal EnumerableItemOf(T Value)

   4:     {

   5:         this.Item = Value;

   6:     }

   7:     

   8:     public T Item { get; private set; }

   9: }

  10:  

  11:  

  12: public static class LinqUtility

  13: {

  14:     public static EnumerableItemOf<T> Of<T>(this IEnumerable<T> Enumerable, T Item)

  15:     {

  16:     

  17:         if (Enumerable != null && Enumerable.Contains(Item))

  18:         {

  19:             return new EnumerableItemOf<T>(Item);

  20:         }

  21:     

  22:         return new EnumerableItemOf<T>(default(T));    

  23:     }

  24: }

Advertisements

Written by Lynn Eriksen

September 20, 2009 at 2:37 am

Posted in Uncategorized

Tagged with ,

One Response

Subscribe to comments with RSS.

  1. if you use foreach instead for statemant, try this:

    c.title) %>

    Victor Cavalcante

    March 14, 2010 at 4:11 pm


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: