find a location for property in a new city

Wednesday 6 July 2011

Custom Model Binder for binding drop downs into a DateTime in MVC

I have a Nullable DateTime Property in my Model I want to bind painlessly with three drop down select boxes I have for Day Month and Year respectively.

First thing to do is to make a new shiny custom model binder. I have done mine by inheriting from DefaultModelBinder (which you will need to include System.Web.Mvc to access).
using System;
using System.ComponentModel;
using System.Web.Mvc;

namespace Infrastructure.OFP.ModelBinders
{
    public class MyUserModelBinder : DefaultModelBinder
    {
        protected override void BindProperty(ControllerContext controllerContext,
            ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor)
        {
            if (propertyDescriptor.PropertyType == typeof(DateTime?)
                && propertyDescriptor.Name == "DateOfBirth")
            {
                var request = controllerContext.HttpContext.Request;
                var prefix = propertyDescriptor.Name;
    
//remember I am a Brit so this will give me dd/mm/yyyy format - this may not work for you :)
//also since this is a binder specific for one particular form the hardcoding of
//    MyUser.DateOfBirth is suitable
//AND... I am using Value because I am using a Nullable
                var date = string.Format("{0}/{1}/{2}",
                           request["MyUser.DateOfBirth.Value.Day"],
                           request["MyUser.DateOfBirth.Value.Month"],
                           request["MyUser.DateOfBirth.Value.Year"]);

                DateTime dateOfBirth;
                if (DateTime.TryParse(date, out dateOfBirth))
                {
                    SetProperty(controllerContext, bindingContext,
                                propertyDescriptor, dateOfBirth);
                    return;
                }
                else
                {
                    bindingContext.ModelState.AddModelError("DateOfBirth",
                           "Date was not recognised");
                    return;
                }
            }
            base.BindProperty(controllerContext, bindingContext, propertyDescriptor);
        }
    }
}

This new Model Binder will need to be registered to be used when binding a MyUser object. You do this in the Global.asax Application_Start() like so:
protected void Application_Start()
{
    ModelBinders.Binders[typeof(MyUser)] = new MyUserModelBinder();
    AreaRegistration.RegisterAllAreas();
    RegisterRoutes(RouteTable.Routes);
}

For reference the drop downs I created to populate the nullable DateTime property of DateOfBirth is as follows:
@Html.DropDownListFor(m => m.MyUser.DateOfBirth.Value.Day,
                      new SelectList(Model.Days, "Key", "Value"))
@Html.DropDownListFor(m => m.MyUser.DateOfBirth.Value.Month,
                      new SelectList(Model.Months, "Key", "Value"))
@Html.DropDownListFor(m => m.MyUser.DateOfBirth.Value.Year,
                      new SelectList(Model.Years, "Key", "Value"))
@Html.ValidationMessageFor(m => m.MyUser.DateOfBirth)

This works as I expected it to. It validates the property as expected using the DataAnnotations that I have defined for it.

Follow britishdev on Twitter

9 comments:

  1. Hello Colin,

    Any chance you can provide a complete example of your solution?

    Thanks,
    Andreas

    ReplyDelete
  2. Yep, complete example is what would help. Thank you,

    ReplyDelete
    Replies
    1. Admittedly the article is a little blunt and straight down to code, but what is it you feel is incomplete about the example exactly? Maybe I can elaborate. Although bear in mind I wrote this almost a year ago :)

      Delete
  3. This was extremely helpful Colin. Great work!

    ReplyDelete
  4. Motifz Designer Lawn. 1, 2 & 3 Piece Unstitched Premium Embroidered Lawn 2019, Premium embroidered Lawn, Premium lawn, Premium lawn 2019, Motifz, Premium lawn in Pakistan. Shipping worldwide. Stitching option available.

    ReplyDelete
  5. Buy online wholesale printed custom lipstick boxes and packaging at easy prices and shipping worldwide, with 24/7 customer support. Get a free custom quote now!!

    ReplyDelete
  6. Packaging town is a one-stop solution for the short-run tincure packaging needs, and supplies. At affordable prices. Request a free quote now.

    ReplyDelete
  7. Buy basic cotton tees online from ndure at easy prices delivered at your doorstep. Get free shipping

    ReplyDelete
  8. Buy men footwear online in Pakistan from Al-Fatah at best prices delivered at your doorstep. Get free shipping.

    ReplyDelete