Home MVC Storefront

ASP.NET MVC: List Helper Extension Method

When I created the prototype of the MVC Toolkit (the HTML Helpers), there was a method in there that I was particularly fond of: ToFormattedList(). This Extension method would take an IEnumerable (or IEnumerable<T>) and create a simple formatted list out of it. It's since been replaced, but I liked it so much I thought I'd do a quick post about it.

This is a Public, Service, Announcement
There may be better ways to do this, but sometimes it's nice to just use one line of code to create an ordered list or unordered list. Rather than beat this to death, here's the code:

        /// <summary>
        /// Creates a formatted list of items based on the passed in format
        /// </summary>
        public static string ToFormattedList(this IEnumerable list, ListType listType) {

            string outerListFormat = "";
            string listFormat = "";

            switch (listType) {
                case ListType.Ordered:
                    outerListFormat = "<ol>{0}</ol>";
                    listFormat = "<li>{0}</li>";
                    break;
                case ListType.Unordered:
                    outerListFormat = "<ul>{0}</ul>";
                    listFormat = "<li>{0}</li>";
                    break;
                case ListType.TableCell:
                    outerListFormat = "{0}";
                    listFormat = "<td>{0}</td>";
                    break;
                default:
                    break;
            }


            return string.Format(outerListFormat, ToFormattedList(list, listFormat));
        }

        /// <summary>
        /// Creates a formatted list of items based on the passed in format
        /// </summary>
        /// <param name="list">The item list</param>
        /// <param name="format">The single-place format string to use</param>
        public static string ToFormattedList(IEnumerable list, string format) {

            StringBuilder sb = new StringBuilder();
            foreach (object item in list) {
                sb.AppendFormat(format, item.ToString());
            }

            return sb.ToString();

        }

I'm working with enums so I don't have to pass in strings (although I still can with the overload). My enum is declared like this:

    /// <summary>
    /// Types of HTML Lists
    /// </summary>
    public enum ListType {
        Ordered,
        Unordered,
        TableCell
    }

You can have whatever lists you like here - options, table rows - whatever you need. I'm keeping this simple for the sake of the blog post here.

To use this, Extension method, you first need an Enumerable object. I'll use a string array, but any object will do. The ToString() method will be called on that object so you might want to override it's core methods if you're not using a primitive.

I've created a string array to test this method:

string[] names = new string[] { "larry", "moe", "curly" };

To output this as a list, all I need to do is reference the new "ToFormattedList()" method:

<%=names.ToFormattedList(ListType.Unordered)%>

This will output:

  • larry
  • moe
  • curly

    Hope you find this helpful.

     

     

  • jdc avatar
    jdc says:
    Wednesday, June 25, 2008

    I'm having some trouble getting the latest download to run locally. Maybe just IR st00pid or something... Here's what I'm doing:

    1. Download and extract.

    2. Restore database.

    3. Change references to "localhost" in connection strings to "myserver\SQLEXPRESS" because I'm running SQL Server Express.

    4. Build and run the app.

    What I keep getting - both when trying to hit any page and when running the unit tests - are several "object not defined" errors pointing at code in the Execute method of the Controller class.

    Is there a setup step I'm missing somewhere? The download seems to have all of the external DLL references it needs, so I don't think it's a versioning problem with MVC. Any ideas?


    Steven Harman avatar
    Steven Harman says:
    Wednesday, June 25, 2008

    You knew this was coming...

    I'm guessing you're not using ReSharper to help you refactor your code b/c I see some leftover, unused code in ToFormattedList(this IEnumerable list, ListType listType). Namely, you don't need the first two lines b/c the variables are never used.

    Also, what's with all the ceremony? Getting an Enumerator and then calling MoveNext... why not iterate over the items with a foreach. Or even better, use something like an Each() extension method on IEnumerable to get Ruby-esq blocks? stevenharman.net/.../get-ruby-esq-ea

    Just wanted to nit-pick. :)


    Rob Conery avatar
    Rob Conery says:
    Wednesday, June 25, 2008

    Hi Steve :) love to refactor this. There was a reason for MoveNext() but I can't remember what it is :). Don't know if I follow you about the un-needed code; but hit me! Whaddya got?


    Troy Goode avatar
    Troy Goode says:
    Wednesday, June 25, 2008

    Rob,

    Steve is pointing out that the following lines:

    StringBuilder sb = new StringBuilder();

    IEnumerator en = list.GetEnumerator();

    ... aren't necessary because the variables "sb" and "en" are not used after they are declared.


    David avatar
    David says:
    Wednesday, June 25, 2008

    I think Steve's referring to this in the first method:

    public static string ToFormattedList(this IEnumerable list, ListType listType) {

    // -> StringBuilder sb = new StringBuilder();

    // -> IEnumerator en = list.GetEnumerator();

    ...


    Rob Conery avatar
    Rob Conery says:
    Wednesday, June 25, 2008

    What two lines ? :):) Edited - jeez i'm going blind!


    tufi avatar
    tufi says:
    Thursday, June 26, 2008

    i also have exactly the same issue as jdc has. same steps same errors with object not defined.

    I could not figure out the problem until now.


    jdc avatar
    jdc says:
    Thursday, June 26, 2008

    @tufi: When you say "I could not figure out the problem until now" does that mean you figured out the problem? What was it?


    tufi avatar
    tufi says:
    Thursday, June 26, 2008

    no i haven't found any solution sorry , i wanted to say that i am still trying to figure out what is the problem.

    i get "Object reference not set to an instance of an object" error.


    tufi avatar
    tufi says:
    Thursday, June 26, 2008

    looks like that overrided method GetControllerInstance(Type controllerType) from StructureMapControllerFactory is getting a bad controllerType argument for me.


    Joe Chung avatar
    Joe Chung says:
    Friday, June 27, 2008

    public static class ListFormatter

    {

    private static readonly IDictionary<ListType, ListFormats> formatters = new Dictionary<ListType, ListFormats>();

    static ListFormatter()

    {

    formatters.Add(ListType.Ordered, new ListFormats() { ItemFormat = "<li>{0}</li>", ListFormat = "<ol>{0}</ol>" });

    formatters.Add(ListType.Unordered, new ListFormats() { ItemFormat = "<li>{0}</li>", ListFormat = "<ul>{0}</ul>" });

    formatters.Add(ListType.TableCell, new ListFormats() { ItemFormat = "<td>{0}</td>", ListFormat = "{0}" });

    formatters.Add(ListType.TableRow, new ListFormats() { ItemFormat = "<tr>{0}</tr>", ListFormat = "<table>{0}<table>" });

    }

    public static string ToFormattedList<T>(IEnumerable<T> items, ListType type)

    {

    return ToFormattedList<T>(items, type, s => s.ToString());

    }

    public static string ToFormattedList<T>(IEnumerable<T> items, ListType type, Func<T, string> toString)

    {

    string listFormat = formatters[type].ListFormat;

    string itemFormat = formatters[type].ItemFormat;

    var itemsProjected = items.Select(item => string.Format(itemFormat, toString(item)));

    return string.Format(listFormat, string.Join(string.Empty, itemsProjected.ToArray()));

    }

    }

    Generics FTW! ToFormattedList<T> is really a one-liner, but I broke it up into multiple statements to make it less cryptic.

    Rather than relying on ToString(), you can pass a delegate/lambda to format the string however you like.

    PS. I wish that Graffiti didn't munge my code. :(



    Search Me
    Index Of MVC Screencasts

    You can watch all of the MVC Screencasts up at ASP.NET, and even leave comments if you like.

    Subscribe

    Popular Posts
     
    My Tweets
    • @mattberther do you really want to use the words "fair", "balanced" and "Hannity" in the same sentence? :):)
    • @ryanlanciaux McCain is becoming a national embarrasment like Bush before him. Cheapens our political process and makes us look like idiots
    • @ryanlanciaux The basics I spose - the ability to speak in full sentences, details about their plans, no overt smears and lies... like that
    • Time Magazine: "what a desperate empty embarrassment the McCain campaign has become". Have to agree. http://tinyurl.com/3kygnq
    • How does O'Reilly keep his job? http://tinyurl.com/3zw5r4
      About Me



    Hi! My name is Rob Conery and I work at Microsoft. I am the Creator of SubSonic and was the Chief Architect of the Commerce Starter Kit (a free, Open Source eCommerce platform for .NET)

    I live in Kauai, HI with my family, and when my clients aren't looking, I sometimes write things on my blog (giving away secrets of incalculable value).