tags:

views:

324

answers:

2

Often I find myself filling ASP.NET repeaters with items that need the CSS class set depending on index: 'first' for index 0, 'last' for index (length-1), and 'mid' in the middle:

_repeater.DataSource = from f in foos
           select new
           {
             ...,
          CssClass = MakeCssClass( foos, f )
           };


private static string MakeCssClass( Foo[] foos, Foo f )
{
  var index = Array.IndexOf( foos, f );

  if( index == 0 )
  {
    return "first";
  }
  else if( index == foos.Length - 1 )
  {
    return "last";
  }
  else
  {
    return "mid";
  }
}

Is there a nicer way I can achieve this (eg using lambda functions)? If I try I get CS0828, "Cannot assign lambda expression to anonymous type property".

+4  A: 

You might be interested in my SmartEnumerable type in MiscUtil.

From the usage page, there's an example:

using System;
using System.Collections.Generic;

using MiscUtil.Collections;

class Example
{
    static void Main(string[] args)
    {
        List<string> list = new List<string>();
        list.Add("a");
        list.Add("b");
        list.Add("c");
        list.Add("d");
        list.Add("e");

        foreach (SmartEnumerable<string>.Entry entry in
                 new SmartEnumerable<string>(list))
        {
            Console.WriteLine ("{0,-7} {1} ({2}) {3}",
                               entry.IsLast  ? "Last ->" : "",
                               entry.Value,
                               entry.Index,
                               entry.IsFirst ? "<- First" : "");
        }
    }
}

With implicitly typed variables and a bit more type inference the syntax could be tidied up quite easily. I must get round to that some time, but the basics are already there.

Jon Skeet
Lovely, thanks. I added a helper method to SmartEnumerable.Entry:public V FirstMidLast<V>( V first, V mid, V last ){ if( IsFirst ) { return first; } else if( IsLast ) { return last; } else { return mid; }}
stusmith
A: 

Here's a clever way to get those mids - Skip, Reverse, Skip (what is this, UNO?).

List<SomeClass> myList = foos
  .Select(f => new SomeClass{ ..., CssClass=string.Empty })
  .ToList();

if (myList.Any())
{        
  myList.First().CssClass = "first";
  myList.Last().CssClass = "last";
  foreach(var z in myList.Skip(1).Reverse().Skip(1))
  {
    z.CssClass = "mid";
  }
}

_repeater.DataSource = myList;

Here's a better way for this problem statement.

List<SomeClass> myList = foos
  .Select(f => new SomeClass{ ..., CssClass="mid" })
  .ToList();

if (myList.Any())
{    
  myList.First().CssClass = "first";
  myList.Last().CssClass = "last";
}

_repeater.DataSource = myList;

Of course, neither of these technique will work if you are using anonymous types (their properties are read-only). Don't use anonymous types for query results.

David B
I prefer anonymous types, as it gives you a certain amount of compile-time checking between database schema and ASP.NET pages.
stusmith