-->
Bookmark and Share

BetterCalendar

View a screen shot of this control.

Storing Non-selectable Dates

Within the BetterCalendar.Render method, a System.Web.UI.WebControls.CalendarDay and a System.Web.UI.WebControls.TableCell object is created for each day in the calendar display. The OnDayRender event is raised and these two objects are passed to any DayRender event handler assigned to the control, just like Calendar does.

After control returns from the event handler, the CalendarDay.IsSelectable property is checked. If it was set to false, that day's date is added to an ArrayList.

// Create a list for storing nonselectable dates.
ArrayList nonselectableDates = new ArrayList();

for (...)

  for (...)

    ...

    // Create a CalendarDay and a TableCell for the date.
    CalendarDay day = this.Day(date);
    TableCell cell = this.Cell(day);

    // Raise the OnDayRender event.
    this.OnDayRender(cell, day);

    // If the day was marked nonselectable, add it to the list.
    if (!day.IsSelectable)
      nonselectableDates.Add(day.Date.ToShortDateString());

The obvious thing to do would be to save this list to the view state. However, since the control is being rendered, this will not work because the control's SaveViewState method has already been called.

Instead, the data is stored in a hidden field added to the page. A couple of methods are defined to handle the conversion of the dates in the ArrayList to a suitable string value that can be stored in a hidden form field and subsequently restored.

//
// Saves a list of dates to the hidden form field.
//
private void SaveNonselectableDates(ArrayList dates)
{
  // Build a string array by converting each date to a day count
  // value.
  string[] list = new string[dates.Count];
  for (int i = 0; i < list.Length; i++)
    list[i] = this.DayCountFromDate(
      DateTime.Parse(dates[i].ToString())).ToString();

  // Get the hidden field name.
  string fieldName  = this.GetHiddenFieldName();

  // For the field value, create a comma-separated list from the day
  // count values.
  string fieldValue =
    HttpUtility.HtmlAttributeEncode(String.Join(",", list));

  // Add the hidden form field to the page.
  this.Page.RegisterHiddenField(fieldName, fieldValue);
}

//
// Returns a list of dates stored in the hidden form field.
//
private ArrayList LoadNonselectableDates()
{
  // Get the value stored in the hidden form field.
  string fieldName  = this.GetHiddenFieldName();
  string fieldValue = this.Page.Request.Form[fieldName];

  // Extract the individual day count values.
  string[] list = fieldValue.Split(',');

  // Convert those values to dates and store them in an array list.
  ArrayList dates = new ArrayList();
  foreach (string s in list)
    dates.Add(this.DateFromDayCount(Int32.Parse(s)));

return dates;
}

//
// Returns the name of the hidden field used to store nonselectable
// dates on the form.
//
private string GetHiddenFieldName()
{
  // Create a unique field name.
  return String.Format("{0}_NonselectableDates", this.ClientID);
}

Within the RaisePostBackEvent, when a range of dates is being selected, we can load this list and use it to remove those dates.

...

this.SelectedDates.Clear();
this.SelectedDates.SelectRange(date, date.AddDays(n - 1));

// If SelectAllInRange is false, remove any dates found
// in the nonselectable date list.
if (!this.SelectAllInRange)
{
  ArrayList nonselectableDates = this.LoadNonselectableDates();
  foreach(DateTime badDate in nonselectableDates)
    this.SelectedDates.Remove(badDate);
}

Downloads