Archive for December, 2009

LightSpeed 3.0 Released

Tuesday, December 15th, 2009

The guys at Mindscape have released the latest version of their Lightspeed ORM.

Read more about it here.

I look forward to downloading it and having a play.

ASP.Net MVC Option Group DropDown Control

Tuesday, December 15th, 2009

Option Groups for drop down lists have been an HTML feature for many years now but have never been supported in any Asp.Net control. It was a bit of a shame recently whilst working on a new Asp.Net MVC web site to find that its still not possible to do out of the box.

optiongroup

However the good thing about MVC is that its a really easy¬† to write your own custom controls in the shape of HTML helpers so I thought I’d go about writing my own.

What did I want the control to do?

Firstly I wanted it to be strongly typed so no magic strings. I also wanted to be able to pass the control an enumerable collection of objects and use lambda expressions to tell the control which properties to render the text, value and how to group the dropdown items by.


<%= Html.OptionGroupDropDownList(
          ViewData.Model.Cars,
          car =>  car.CountryOfOrigin,
          car => car.Brand,
          car => car.Brand,
          car => car.Brand == "BMW")%>

Line 2 above represents the collection of cars we wish to render as option items.
Line 3 is the property value of a car we wish to group them by.
Line 4 is the property value of a car we wish to use as the option value.
Line 5 is the property value a car we wish to use for the option text.
Line 6 is a condition we can supply to tell the control which drop down item should be selected.

which renders HTML that looks something a little like this:


Ok so the code looks like this..

public static string OptionGroupDropDownList<T, TProperty, TProperty1, TProperty2>
( this HtmlHelper htmlHelper,
  string name,
  string optionLabel,
  IEnumerable<T> collection,
  Func<T, TProperty> optionGroupProperty,
  Func<T, TProperty1> optionValueProperty,
  Func<T, TProperty2> optionTextProperty,
  Func<T, bool> isSelectedCondition)
{
      var groupedCollection = collection.GroupBy(optionGroupProperty);

      // We are trying to generate the Html that looks something like this...
      //<select>
      //  <optgroup label="Swedish Cars">
      //      <option value="volvo">Volvo</option>
      //      <option value="saab">Saab</option>
      //  </optgroup>
      //</select>";
      using (var stringWriter = new StringWriter())
      using (var writer = new HtmlTextWriter(stringWriter))
      {
          writer.AddAttribute(HtmlTextWriterAttribute.Name, name);
          writer.AddAttribute(HtmlTextWriterAttribute.Id, name);
          //<Select>
          writer.RenderBeginTag(HtmlTextWriterTag.Select); 

          if(string.IsNullOrEmpty(optionLabel) == false)
           {
               writer.RenderBeginTag(HtmlTextWriterTag.Option);
               writer.Write(optionLabel);
               writer.RenderEndTag();
            }

           // Group by our optGroup parameter...in the above example that would be
           // "Swedish Cars"
           foreach (var optionGroup in groupedCollection)
           {
                var optionGroupLabel = optionGroup.Key;
                // label="Swedish Cars"
                writer.AddAttribute(Label, optionGroupLabel.ToString());
                writer.RenderBeginTag(Optgroup); //<optgroup>  

                 foreach (var option in optionGroup)
                 {
                   var optionValue = optionValueProperty.Invoke(option).ToString();
                   var optionText = optionTextProperty.Invoke(option).ToString();

                   var isOptionSelected = isSelectedCondition.Invoke(option);

                   if (isOptionSelected)
                     writer.AddAttribute(HtmlTextWriterAttribute.Selected, "true");

                   // value = "volvo"
                   writer.AddAttribute(HtmlTextWriterAttribute.Value, optionValue); 

                   // <option>
                   writer.RenderBeginTag(HtmlTextWriterTag.Option);
                   // Volvo
                   writer.Write(optionText);
                   // </option>
                   writer.RenderEndTag();
                  }
                  // </optiongroup>
                   writer.RenderEndTag();
                }
                 //</Select>
                writer.RenderEndTag();

                return stringWriter.ToString();
            }
        }

Mocking HtmlHelpers in ASP.Net MVC

Friday, December 4th, 2009

NB: This post relates to version 1 of ASP.Net MVC

I recently added a static extension method for generating a custom drop down list and wanted to test it using Rhino Mocks (version 3.5).
One issue I kept banging my head against was how to create a Mock HtmlHelper in order to call the method correctly.
A number of posts later, and various attempts at using some of the sample code and I finally came across this post detailing a bunch of MVC tests.

After a minor amount of customising, I ended up with the following, which works like a charm for me to use in my tests.

        ///
        /// Creates a HTML helper for use in tests.
        ///
        private HtmlHelper CreateHtmlHelper()
        {
            var userControl = new ViewUserControl();
            var container = new ViewPage();
            container.Controls.Add(userControl);
            var context = MockRepository.GenerateMock<ViewContext>();
            userControl.ViewContext = context;

            return userControl.Html;
        }