none
DatePicker and manual entry issues

    Question

  • I've seen this forum post regarding manual entry:  http://silverlight.net/forums/p/20135/69929.aspx

    This is basically the same problem I am having.  I need a way to enforce the DisplayDateStart and DisplayDateEnd when the user manually enters the date.  I understand the response in that post about these properties being Display specific. 

    Anyway, I've resigned myself to having to do something about this in the SelectedDateChanged event.  This is my attempt:

    private void DatePicker_SelectedDateChanged(object sender, SelectionChangedEventArgs e)
            {
                DatePicker datePicker = sender as DatePicker;
               
                if (datePicker != null)
                {
                    if (e.AddedItems != null && e.AddedItems.Count > 0)
                    {
                        DateTime newDate = (DateTime) e.AddedItems[0];
                        if (newDate < datePicker.DisplayDateStart || newDate > datePicker.DisplayDateEnd)
                        {
                            datePicker.SelectedDate = null;
                        }   
                    }                   
                }
            }

    However, there is still what I would think a bug.  If I have DisplayDateStart of 04/01/09 and DisplayDateEnd of 04/01/10 and the user types 04/01/12, the SelectedDateChanged event fires and I reset the SelectedDate to null and everything looks good until you open the popup calendar and now the DisplayDateEnd is now set to 04/01/12. 

    Can anyone shed light or confirm that this is a bug?

    Thanks in advance

     

    Tuesday, March 24, 2009 12:50 PM

Answers

  • Thanks everyone for your responses.  I gave up trying to make it work with the standard DatePicker.  

    I have taken the source and used it as a guide to create a custom DatePicker that actually uses the DisplayDateStart and DisplayDateEnd properties to enforce the user's text input. It also adds a DisableWeekends property that was very helpful my recent client (financial institution).  Once I can come up for air, I'll publish the source to this new DatePicker to get more eyes on it and as there's probably a better solution. 

    The main issue here was resolved in about 1-1/2 lines of code.  This is the DatePicker.TextParse method - see my comment (RR) where I changed it.

    private DateTime? ParseText(string text)
    {
                DateTime newSelectedDate;

                //TryParse is not used in order to be able to pass the exception to the TextParseError event
                try
                {
                    newSelectedDate = DateTime.Parse(text, DateTimeHelper.GetCurrentDateFormat());

    // RR:  This added to enforce the manually entered date to fall within the Displayed Date Range
                    bool isWithinValidDisplayRange = (newSelectedDate >= this.DisplayDateStart && newSelectedDate <= this.DisplayDateEnd);

                    //RR -  ORIGINAL:   if (Calendar.IsValidDateSelection(this._calendar, newSelectedDate))
                 

     if (isWithinValidDisplayRange && !BlackoutDates.Contains(newSelectedDate))
                    {
                        return newSelectedDate;
                    }
                    else
                    {
                        DatePickerDateValidationErrorEventArgs dateValidationError = new DatePickerDateValidationErrorEventArgs(new ArgumentOutOfRangeException("text",Resource.Calendar_OnSelectedDateChanged_InvalidValue), text);
                        OnDateValidationError(dateValidationError);

                        if (dateValidationError.ThrowException)
                        {
                            throw dateValidationError.Exception;
                        }
                    }
                }
                catch (FormatException ex)
                {
                    DatePickerDateValidationErrorEventArgs textParseError = new DatePickerDateValidationErrorEventArgs(ex, text);
                    OnDateValidationError(textParseError);

                    if (textParseError.ThrowException)
                    {
                        throw textParseError.Exception;
                    }
                }
                return null;
            } 

     

    This worked for me although I realize that the DisplayDateStart and DisplayDateEnd were not designed to be anything other than the display's DateStart and DateEnd.  That just seemed useless to me if the user can type in anything they want (even 01/01/0001 works and rebuilds the calendar to do it). 

    Love to hear any better ideas for how to handle this.  This did require that do a few other things to decouple the DatePicker.cs from the internal methods/events that it needed access on Calendar and other code. 

    I'll blog the whole thing and post the result shortly.   I'll return here to post a link. 

     
    Saturday, March 28, 2009 12:12 PM

All replies

  •  I think this is a bug.  I just checked on some datepickers I'm doing the same thing with and the property DisplayDateEnd doesn't actually change but the dates that are shown in the Calendar popup are incorrect.

    Friday, March 27, 2009 5:54 PM
  • This is a bug. I will report this to the Silverlight Toolkit Team.

    Friday, March 27, 2009 7:00 PM
  •  I don't see a great way around this.  Reflector indicates that the underlying Calendar is helpfully extending it's DisplayDateStart and DisplayDateEnd when it's DisplayDate is changed by the DatePicker.  If they had chosen to use the SelectedDate property of the Calendar when they were designing the DatePicker this would have thrown an exception instead of extending the visible dates.  I don't think DatePicker was really created with restricting user input in mind.

    The underlying Calendar is private and isn't exposed as a dependency property. I don't know if you can get to it through reflection but I think that's a bit much for this.

    Friday, March 27, 2009 7:05 PM
  • Thanks everyone for your responses.  I gave up trying to make it work with the standard DatePicker.  

    I have taken the source and used it as a guide to create a custom DatePicker that actually uses the DisplayDateStart and DisplayDateEnd properties to enforce the user's text input. It also adds a DisableWeekends property that was very helpful my recent client (financial institution).  Once I can come up for air, I'll publish the source to this new DatePicker to get more eyes on it and as there's probably a better solution. 

    The main issue here was resolved in about 1-1/2 lines of code.  This is the DatePicker.TextParse method - see my comment (RR) where I changed it.

    private DateTime? ParseText(string text)
    {
                DateTime newSelectedDate;

                //TryParse is not used in order to be able to pass the exception to the TextParseError event
                try
                {
                    newSelectedDate = DateTime.Parse(text, DateTimeHelper.GetCurrentDateFormat());

    // RR:  This added to enforce the manually entered date to fall within the Displayed Date Range
                    bool isWithinValidDisplayRange = (newSelectedDate >= this.DisplayDateStart && newSelectedDate <= this.DisplayDateEnd);

                    //RR -  ORIGINAL:   if (Calendar.IsValidDateSelection(this._calendar, newSelectedDate))
               if (isWithinValidDisplayRange && !BlackoutDates.Contains(newSelectedDate))
                    {
                        return newSelectedDate;
                    }
                    else
                    {
                        DatePickerDateValidationErrorEventArgs dateValidationError = new DatePickerDateValidationErrorEventArgs(new ArgumentOutOfRangeException("text",Resource.Calendar_OnSelectedDateChanged_InvalidValue), text);
                        OnDateValidationError(dateValidationError);

                        if (dateValidationError.ThrowException)
                        {
                            throw dateValidationError.Exception;
                        }
                    }
                }
                catch (FormatException ex)
                {
                    DatePickerDateValidationErrorEventArgs textParseError = new DatePickerDateValidationErrorEventArgs(ex, text);
                    OnDateValidationError(textParseError);

                    if (textParseError.ThrowException)
                    {
                        throw textParseError.Exception;
                    }
                }
                return null;
            } 

     

    This worked for me although I realize that the DisplayDateStart and DisplayDateEnd were not designed to be anything other than the display's DateStart and DateEnd.  That just seemed useless to me if the user can type in anything they want (even 01/01/0001 works and rebuilds the calendar to do it). 

    Love to hear any better ideas for how to handle this.  This did require me to do a few other things to decouple the DatePicker.cs from the internal methods/events that it needed access to on Calendar and other code. 

    I'll blog the whole thing and post the result shortly.   I'll return here to post a link. 

    Saturday, March 28, 2009 12:12 PM
  • Thanks everyone for your responses.  I gave up trying to make it work with the standard DatePicker.  

    I have taken the source and used it as a guide to create a custom DatePicker that actually uses the DisplayDateStart and DisplayDateEnd properties to enforce the user's text input. It also adds a DisableWeekends property that was very helpful my recent client (financial institution).  Once I can come up for air, I'll publish the source to this new DatePicker to get more eyes on it and as there's probably a better solution. 

    The main issue here was resolved in about 1-1/2 lines of code.  This is the DatePicker.TextParse method - see my comment (RR) where I changed it.

    private DateTime? ParseText(string text)
    {
                DateTime newSelectedDate;

                //TryParse is not used in order to be able to pass the exception to the TextParseError event
                try
                {
                    newSelectedDate = DateTime.Parse(text, DateTimeHelper.GetCurrentDateFormat());

    // RR:  This added to enforce the manually entered date to fall within the Displayed Date Range
                    bool isWithinValidDisplayRange = (newSelectedDate >= this.DisplayDateStart && newSelectedDate <= this.DisplayDateEnd);

                    //RR -  ORIGINAL:   if (Calendar.IsValidDateSelection(this._calendar, newSelectedDate))
                 

     if (isWithinValidDisplayRange && !BlackoutDates.Contains(newSelectedDate))
                    {
                        return newSelectedDate;
                    }
                    else
                    {
                        DatePickerDateValidationErrorEventArgs dateValidationError = new DatePickerDateValidationErrorEventArgs(new ArgumentOutOfRangeException("text",Resource.Calendar_OnSelectedDateChanged_InvalidValue), text);
                        OnDateValidationError(dateValidationError);

                        if (dateValidationError.ThrowException)
                        {
                            throw dateValidationError.Exception;
                        }
                    }
                }
                catch (FormatException ex)
                {
                    DatePickerDateValidationErrorEventArgs textParseError = new DatePickerDateValidationErrorEventArgs(ex, text);
                    OnDateValidationError(textParseError);

                    if (textParseError.ThrowException)
                    {
                        throw textParseError.Exception;
                    }
                }
                return null;
            } 

     

    This worked for me although I realize that the DisplayDateStart and DisplayDateEnd were not designed to be anything other than the display's DateStart and DateEnd.  That just seemed useless to me if the user can type in anything they want (even 01/01/0001 works and rebuilds the calendar to do it). 

    Love to hear any better ideas for how to handle this.  This did require that do a few other things to decouple the DatePicker.cs from the internal methods/events that it needed access on Calendar and other code. 

    I'll blog the whole thing and post the result shortly.   I'll return here to post a link. 

     
    Saturday, March 28, 2009 12:12 PM
  • Thanks everyone for your responses.  I gave up trying to make it work with the standard DatePicker.  

    I have taken the source and used it as a guide to create a custom DatePicker that actually uses the DisplayDateStart and DisplayDateEnd properties to enforce the user's text input. It also adds a DisableWeekends property that was very helpful my recent client (financial institution).  Once I can come up for air, I'll publish the source to this new DatePicker to get more eyes on it and as there's probably a better solution. 

    The main issue here was resolved in about 1-1/2 lines of code.  This is the DatePicker.TextParse method - see my comment (RR) where I changed it.

    private DateTime? ParseText(string text)
    {
                DateTime newSelectedDate;

                //TryParse is not used in order to be able to pass the exception to the TextParseError event
                try
                {
                    newSelectedDate = DateTime.Parse(text, DateTimeHelper.GetCurrentDateFormat());

    // RR:  This added to enforce the manually entered date to fall within the Displayed Date Range
                    bool isWithinValidDisplayRange = (newSelectedDate >= this.DisplayDateStart && newSelectedDate <= this.DisplayDateEnd);

                    //RR -  ORIGINAL:   if (Calendar.IsValidDateSelection(this._calendar, newSelectedDate))
                 

     if (isWithinValidDisplayRange && !BlackoutDates.Contains(newSelectedDate))
                    {
                        return newSelectedDate;
                    }
                    else
                    {
                        DatePickerDateValidationErrorEventArgs dateValidationError = new DatePickerDateValidationErrorEventArgs(new ArgumentOutOfRangeException("text",Resource.Calendar_OnSelectedDateChanged_InvalidValue), text);
                        OnDateValidationError(dateValidationError);

                        if (dateValidationError.ThrowException)
                        {
                            throw dateValidationError.Exception;
                        }
                    }
                }
                catch (FormatException ex)
                {
                    DatePickerDateValidationErrorEventArgs textParseError = new DatePickerDateValidationErrorEventArgs(ex, text);
                    OnDateValidationError(textParseError);

                    if (textParseError.ThrowException)
                    {
                        throw textParseError.Exception;
                    }
                }
                return null;
            } 

     

    This worked for me although I realize that the DisplayDateStart and DisplayDateEnd were not designed to be anything other than the display's DateStart and DateEnd.  That just seemed useless to me if the user can type in anything they want (even 01/01/0001 works and rebuilds the calendar to do it). 

    Love to hear any better ideas for how to handle this.  This did require that do a few other things to decouple the DatePicker.cs from the internal methods/events that it needed access on Calendar and other code. 

    I'll blog the whole thing and post the result shortly.   I'll return here to post a link. 

     
    Saturday, March 28, 2009 12:12 PM