ASP.NET mvc 2 - binding a birth date with drop downs
In ASP.NET MVC 2, how would you go about binding a view model property that is a DateTime where the application must have 3 drop down lists for choosing month, day, year?I've read Scott H.'s blog post about binding dates some time ago, and that seems entirely too convoluted for such a simple case. Surely there's a cleaner / better way to do it?
Whatever solution I use, I would like to retain built-in validation using the DataAnnotations stuff, and I'd also like to be able to specify a min / max date range using a validation attribute.
My first thought was a simple custom model binder like so:
protected override void BindProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor)
{
var model = bindingContext.Model as RsvpViewModel;
var form = controllerContext.HttpContext.Request.Form;
if (model == null)
throw new ArgumentException("bindingContext.Model");
if (propertyDescriptor.Name.Equals("BirthDate"))
{
if (!string.IsNullOrEmpty(form["BirthYear"]) &&
!string.IsNullOrEmpty(form["BirthMonth"]) &&
!string.IsNullOrEmpty(form["BirthDay"]))
{
try
{
var yy = int.Parse(form["BirthYear"]);
var mm = int.Parse(form["BirthMonth"]);
var dd = int.Parse(form["BirthDay"]);
model.BirthDate = new DateTime(yy, mm, dd);
return;
}
catch (Exception)
{
model.BirthDate = DateTime.MinValue;
return;
}
}
}
base.BindProperty(controllerContext, bindingContext, propertyDescriptor);
}
Then I tried creating a DateTimeAttribute to do the validation, but ran into some difficulty specifying a date range in the attribute declaration because attribute parameter types are limited, and DateTime is not one of the allowable types.
I ended up creating an IDateRangeProvider interface and an implementation specific to birth dates like so:
public interface IDateRangeProvider
{
DateTime GetMin();
DateTime GetMax();
}
public class BirthDateRangeProvider : IDateRangeProvider
{
public DateTime GetMin()
{
return DateTime.Now.Date.AddYears(-100);
}
public DateTime GetMax()
{
return DateTime.Now.Date;
}
}
This allowed m开发者_开发知识库e to use a DateTime property on my view model and retain all of the build in goodness...
[DisplayName("Date of Birth:")]
[Required(ErrorMessage = "Date of birth is required")]
[DateTime(ErrorMessage = "Date of birth is invalid", RangeProvider=typeof(BirthDateRangeProvider))]
public DateTime? BirthDate { get; set; }
But really, the whole solution smells of overengineering and overthinking it. Isn't there a better way?
create seprate 3 Dropdownlist and add required validation attribute for them.
and use BdateList,BMonthList to populate your DropdownList
[DisplayName("Date of Birth ")]
public DateTime? Birthdate { get; set; }
[Required(ErrorMessage = "Date is required")]
public int BirthDateDate { get; set; }
[Required(ErrorMessage = "Month is required")]
public int BirthDateMonth { get; set; }
[Required(ErrorMessage = "Year is required")]
public int BirthDateYear { get; set; }
public List<System.Web.Mvc.SelectList> BDateList
{
get
{
// create List here
}
}
and in post method you could assign user selected values values to Model BirthDate
BirthDate.Date.AddDays(BirthDateDate -1).AddMonths(BirthDateMonth)
an idea for you
have class birthDate
public class birthDate{
public int day{get;set;}
public int month{get;set;}
public int year{get;set;}
}
now in your entity: set your birthdate element to private
and add the birth date items into the class after you just handle the item for each part together. and process this to one date:)
you can have custom type for birthday which will have properties like
public class BirthDateModel
{
[Required(), Range(1, 12)]
public Int32 BirthMonth { get; set; }
[Required, Range(1, 31)]
[DayShouldBeValid("BirthYear", "BirthMonth")]
public Int32 BirthDay { get; set; }
[Required,Range(1990, 2012)]
public virtual Int32 BirthYear { get; set; }
public DateTimeOffset GetBirthDate()
{
DateTimeOffset birthDate;
if (DateTimeOffset.TryParse(String.Format("{0}-{1}-{2}", BirthMonth, BirthDay, BirthYear), out birthDate))
return birthDate;
// what should be returned here?
return DateTime.MinValue;
}
}
Now create custom validator aka DayShouldBeValid to check for the month and year, the day is valid or not.
Not each part of a date have your own control.
精彩评论