//------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. // //------------------------------------------------------------------------------ namespace System.Web.UI.WebControls { using System.Threading; using System.Globalization; using System.ComponentModel; using System; using System.Web; using System.Web.UI; using System.Web.Util; using System.Collections; using System.ComponentModel.Design; using System.Drawing; using System.Text; using System.IO; using System.Reflection; /// /// Displays a one-month calendar and allows the user to /// view and select a specific day, week, or month. /// [ ControlValueProperty("SelectedDate", typeof(DateTime), "1/1/0001"), DataBindingHandler("System.Web.UI.Design.WebControls.CalendarDataBindingHandler, " + AssemblyRef.SystemDesign), DefaultEvent("SelectionChanged"), DefaultProperty("SelectedDate"), Designer("System.Web.UI.Design.WebControls.CalendarDesigner, " + AssemblyRef.SystemDesign), SupportsEventValidation ] public class Calendar : WebControl, IPostBackEventHandler { private static readonly object EventDayRender = new object(); private static readonly object EventSelectionChanged = new object(); private static readonly object EventVisibleMonthChanged = new object(); private TableItemStyle titleStyle; private TableItemStyle nextPrevStyle; private TableItemStyle dayHeaderStyle; private TableItemStyle selectorStyle; private TableItemStyle dayStyle; private TableItemStyle otherMonthDayStyle; private TableItemStyle todayDayStyle; private TableItemStyle selectedDayStyle; private TableItemStyle weekendDayStyle; private string defaultButtonColorText; private static readonly Color DefaultForeColor = Color.Black; private Color defaultForeColor; private ArrayList dateList; private SelectedDatesCollection selectedDates; private System.Globalization.Calendar threadCalendar; private DateTime minSupportedDate; private DateTime maxSupportedDate; #if DEBUG private bool threadCalendarInitialized; #endif private const string SELECT_RANGE_COMMAND = "R"; private const string NAVIGATE_MONTH_COMMAND = "V"; private static DateTime baseDate = new DateTime(2000, 1, 1); private const int STYLEMASK_DAY = 16; private const int STYLEMASK_UNIQUE = 15; private const int STYLEMASK_SELECTED = 8; private const int STYLEMASK_TODAY = 4; private const int STYLEMASK_OTHERMONTH = 2; private const int STYLEMASK_WEEKEND = 1; private const string ROWBEGINTAG = ""; private const string ROWENDTAG = ""; // Cache commonly used strings. This improves performance and memory usage. private const int cachedNumberMax = 31; private static readonly string[] cachedNumbers = new string [] { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31", }; /// /// Initializes a new instance of the class. /// public Calendar() : base(HtmlTextWriterTag.Table) { } [ Localizable(true), DefaultValue(""), WebCategory("Accessibility"), WebSysDescription(SR.Calendar_Caption) ] public virtual string Caption { get { string s = (string)ViewState["Caption"]; return (s != null) ? s : String.Empty; } set { ViewState["Caption"] = value; } } [ DefaultValue(TableCaptionAlign.NotSet), WebCategory("Accessibility"), WebSysDescription(SR.WebControl_CaptionAlign) ] public virtual TableCaptionAlign CaptionAlign { get { object o = ViewState["CaptionAlign"]; return (o != null) ? (TableCaptionAlign)o : TableCaptionAlign.NotSet; } set { if ((value < TableCaptionAlign.NotSet) || (value > TableCaptionAlign.Right)) { throw new ArgumentOutOfRangeException("value"); } ViewState["CaptionAlign"] = value; } } /// /// Gets or sets the amount of space between cells. /// [ WebCategory("Layout"), DefaultValue(2), WebSysDescription(SR.Calendar_CellPadding) ] public int CellPadding { get { object o = ViewState["CellPadding"]; return((o == null) ? 2 : (int)o); } set { if (value < - 1 ) { throw new ArgumentOutOfRangeException("value"); } ViewState["CellPadding"] = value; } } /// /// Gets or sets the amount of space between the contents of a cell /// and the cell's border. /// [ WebCategory("Layout"), DefaultValue(0), WebSysDescription(SR.Calendar_CellSpacing) ] public int CellSpacing { get { object o = ViewState["CellSpacing"]; return((o == null) ? 0 : (int)o); } set { if (value < -1 ) { throw new ArgumentOutOfRangeException("value"); } ViewState["CellSpacing"] = (int)value; } } /// /// Gets the style property of the day-of-the-week header. This property is read-only. /// [ WebCategory("Styles"), WebSysDescription(SR.Calendar_DayHeaderStyle), DesignerSerializationVisibility(DesignerSerializationVisibility.Content), NotifyParentProperty(true), PersistenceMode(PersistenceMode.InnerProperty) ] public TableItemStyle DayHeaderStyle { get { if (dayHeaderStyle == null) { dayHeaderStyle = new TableItemStyle(); if (IsTrackingViewState) ((IStateManager)dayHeaderStyle).TrackViewState(); } return dayHeaderStyle; } } /// /// Gets or sets /// the format for the names of days. /// [ WebCategory("Appearance"), DefaultValue(DayNameFormat.Short), WebSysDescription(SR.Calendar_DayNameFormat) ] public DayNameFormat DayNameFormat { get { object dnf = ViewState["DayNameFormat"]; return((dnf == null) ? DayNameFormat.Short : (DayNameFormat)dnf); } set { if (value < DayNameFormat.Full || value > DayNameFormat.Shortest) { throw new ArgumentOutOfRangeException("value"); } ViewState["DayNameFormat"] = value; } } /// /// Gets the style properties for the days. This property is read-only. /// [ WebCategory("Styles"), DefaultValue(null), WebSysDescription(SR.Calendar_DayStyle), DesignerSerializationVisibility(DesignerSerializationVisibility.Content), NotifyParentProperty(true), PersistenceMode(PersistenceMode.InnerProperty) ] public TableItemStyle DayStyle { get { if (dayStyle == null) { dayStyle = new TableItemStyle(); if (IsTrackingViewState) ((IStateManager)dayStyle).TrackViewState(); } return dayStyle; } } /// /// Gets /// or sets the day of the week to display in the calendar's first /// column. /// [ WebCategory("Appearance"), DefaultValue(FirstDayOfWeek.Default), WebSysDescription(SR.Calendar_FirstDayOfWeek) ] public FirstDayOfWeek FirstDayOfWeek { get { object o = ViewState["FirstDayOfWeek"]; return((o == null) ? FirstDayOfWeek.Default : (FirstDayOfWeek)o); } set { if (value < FirstDayOfWeek.Sunday || value > FirstDayOfWeek.Default) { throw new ArgumentOutOfRangeException("value"); } ViewState["FirstDayOfWeek"] = value; } } /// /// Gets or sets the text shown for the next month /// navigation hyperlink if the property is set to /// . /// [ Localizable(true), WebCategory("Appearance"), DefaultValue(">"), WebSysDescription(SR.Calendar_NextMonthText) ] public string NextMonthText { get { object s = ViewState["NextMonthText"]; return((s == null) ? ">" : (String) s); } set { ViewState["NextMonthText"] = value; } } /// /// Gets or sets the format of the next and previous month hyperlinks in the /// title. /// [ WebCategory("Appearance"), DefaultValue(NextPrevFormat.CustomText), WebSysDescription(SR.Calendar_NextPrevFormat) ] public NextPrevFormat NextPrevFormat { get { object npf = ViewState["NextPrevFormat"]; return((npf == null) ? NextPrevFormat.CustomText : (NextPrevFormat)npf); } set { if (value < NextPrevFormat.CustomText || value > NextPrevFormat.FullMonth) { throw new ArgumentOutOfRangeException("value"); } ViewState["NextPrevFormat"] = value; } } /// /// Gets the style properties for the next/previous month navigators. This property is /// read-only. /// [ WebCategory("Styles"), WebSysDescription(SR.Calendar_NextPrevStyle), DesignerSerializationVisibility(DesignerSerializationVisibility.Content), NotifyParentProperty(true), PersistenceMode(PersistenceMode.InnerProperty) ] public TableItemStyle NextPrevStyle { get { if (nextPrevStyle == null) { nextPrevStyle = new TableItemStyle(); if (IsTrackingViewState) ((IStateManager)nextPrevStyle).TrackViewState(); } return nextPrevStyle; } } /// /// Gets the style properties for the days from the months preceding and following the current month. /// This property is read-only. /// [ WebCategory("Styles"), DefaultValue(null), WebSysDescription(SR.Calendar_OtherMonthDayStyle), DesignerSerializationVisibility(DesignerSerializationVisibility.Content), NotifyParentProperty(true), PersistenceMode(PersistenceMode.InnerProperty) ] public TableItemStyle OtherMonthDayStyle { get { if (otherMonthDayStyle == null) { otherMonthDayStyle = new TableItemStyle(); if (IsTrackingViewState) ((IStateManager)otherMonthDayStyle).TrackViewState(); } return otherMonthDayStyle; } } /// /// Gets or sets the text shown for the previous month /// navigation hyperlink if the property is set to /// /// . /// [ Localizable(true), WebCategory("Appearance"), DefaultValue("<"), WebSysDescription(SR.Calendar_PrevMonthText) ] public string PrevMonthText { get { object s = ViewState["PrevMonthText"]; return((s == null) ? "<" : (String) s); } set { ViewState["PrevMonthText"] = value; } } public override bool SupportsDisabledAttribute { get { return RenderingCompatibility < VersionUtil.Framework40; } } /// /// Gets or sets the date that is currently selected /// date. /// [ Bindable(true, BindingDirection.TwoWay), DefaultValue(typeof(DateTime), "1/1/0001"), WebSysDescription(SR.Calendar_SelectedDate) ] public DateTime SelectedDate { get { if (SelectedDates.Count == 0) { return DateTime.MinValue; } return SelectedDates[0]; } set { if (value == DateTime.MinValue) { SelectedDates.Clear(); } else { SelectedDates.SelectRange(value, value); } } } /// /// Gets a collection of objects representing days selected on the . This /// property is read-only. /// [ Browsable(false), WebSysDescription(SR.Calendar_SelectedDates), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden) ] public SelectedDatesCollection SelectedDates { get { if (selectedDates == null) { if (dateList == null) { dateList = new ArrayList(); } selectedDates = new SelectedDatesCollection(dateList); } return selectedDates; } } /// /// Gets the style properties for the selected date. This property is read-only. /// [ WebCategory("Styles"), DefaultValue(null), WebSysDescription(SR.Calendar_SelectedDayStyle), DesignerSerializationVisibility(DesignerSerializationVisibility.Content), NotifyParentProperty(true), PersistenceMode(PersistenceMode.InnerProperty) ] public TableItemStyle SelectedDayStyle { get { if (selectedDayStyle == null) { selectedDayStyle = new TableItemStyle(); if (IsTrackingViewState) ((IStateManager)selectedDayStyle).TrackViewState(); } return selectedDayStyle; } } /// /// Gets or sets the date selection capabilities on the /// /// to allow the user to select a day, week, or month. /// [ WebCategory("Behavior"), DefaultValue(CalendarSelectionMode.Day), WebSysDescription(SR.Calendar_SelectionMode) ] public CalendarSelectionMode SelectionMode { get { object csm = ViewState["SelectionMode"]; return((csm == null) ? CalendarSelectionMode.Day : (CalendarSelectionMode)csm); } set { if (value < CalendarSelectionMode.None || value > CalendarSelectionMode.DayWeekMonth) { throw new ArgumentOutOfRangeException("value"); } ViewState["SelectionMode"] = value; } } /// /// Gets or sets the text shown for the month selection in /// the selector column if is /// . /// [ Localizable(true), WebCategory("Appearance"), DefaultValue(">>"), WebSysDescription(SR.Calendar_SelectMonthText) ] public string SelectMonthText { get { object s = ViewState["SelectMonthText"]; return((s == null) ? ">>" : (String) s); } set { ViewState["SelectMonthText"] = value; } } /// /// Gets the style properties for the week and month selectors. This property is read-only. /// [ WebCategory("Styles"), WebSysDescription(SR.Calendar_SelectorStyle), DesignerSerializationVisibility(DesignerSerializationVisibility.Content), NotifyParentProperty(true), PersistenceMode(PersistenceMode.InnerProperty) ] public TableItemStyle SelectorStyle { get { if (selectorStyle == null) { selectorStyle = new TableItemStyle(); if (IsTrackingViewState) ((IStateManager)selectorStyle).TrackViewState(); } return selectorStyle; } } /// /// Gets or sets the text shown for the week selection in /// the selector column if is /// or /// . /// [ Localizable(true), WebCategory("Appearance"), DefaultValue(">"), WebSysDescription(SR.Calendar_SelectWeekText) ] public string SelectWeekText { get { object s = ViewState["SelectWeekText"]; return((s == null) ? ">" : (String) s); } set { ViewState["SelectWeekText"] = value; } } /// /// Gets or sets /// a value indicating whether the days of the week are displayed. /// [ WebCategory("Appearance"), DefaultValue(true), WebSysDescription(SR.Calendar_ShowDayHeader) ] public bool ShowDayHeader { get { object b = ViewState["ShowDayHeader"]; return((b == null) ? true : (bool)b); } set { ViewState["ShowDayHeader"] = value; } } /// /// Gets or set /// a value indicating whether days on the calendar are displayed with a border. /// [ WebCategory("Appearance"), DefaultValue(false), WebSysDescription(SR.Calendar_ShowGridLines) ] public bool ShowGridLines { get { object b= ViewState["ShowGridLines"]; return((b == null) ? false : (bool)b); } set { ViewState["ShowGridLines"] = value; } } /// /// Gets or sets a value indicating whether the /// displays the next and pervious month /// hyperlinks in the title. /// [ WebCategory("Appearance"), DefaultValue(true), WebSysDescription(SR.Calendar_ShowNextPrevMonth) ] public bool ShowNextPrevMonth { get { object b = ViewState["ShowNextPrevMonth"]; return((b == null) ? true : (bool)b); } set { ViewState["ShowNextPrevMonth"] = value; } } /// /// Gets or /// sets a value indicating whether the title is displayed. /// [ WebCategory("Appearance"), DefaultValue(true), WebSysDescription(SR.Calendar_ShowTitle) ] public bool ShowTitle { get { object b = ViewState["ShowTitle"]; return((b == null) ? true : (bool)b); } set { ViewState["ShowTitle"] = value; } } /// /// Gets or sets how the month name is formatted in the title /// bar. /// [ WebCategory("Appearance"), DefaultValue(TitleFormat.MonthYear), WebSysDescription(SR.Calendar_TitleFormat) ] public TitleFormat TitleFormat { get { object tf = ViewState["TitleFormat"]; return((tf == null) ? TitleFormat.MonthYear : (TitleFormat)tf); } set { if (value < TitleFormat.Month || value > TitleFormat.MonthYear) { throw new ArgumentOutOfRangeException("value"); } ViewState["TitleFormat"] = value; } } /// /// Gets the style properties of the title. This property is /// read-only. /// [ WebCategory("Styles"), WebSysDescription(SR.Calendar_TitleStyle), DesignerSerializationVisibility(DesignerSerializationVisibility.Content), NotifyParentProperty(true), PersistenceMode(PersistenceMode.InnerProperty), ] public TableItemStyle TitleStyle { get { if (titleStyle == null) { titleStyle = new TableItemStyle(); if (IsTrackingViewState) ((IStateManager)titleStyle).TrackViewState(); } return titleStyle; } } /// /// Gets the style properties for today's date on the /// . This /// property is read-only. /// [ WebCategory("Styles"), DefaultValue(null), WebSysDescription(SR.Calendar_TodayDayStyle), DesignerSerializationVisibility(DesignerSerializationVisibility.Content), NotifyParentProperty(true), PersistenceMode(PersistenceMode.InnerProperty) ] public TableItemStyle TodayDayStyle { get { if (todayDayStyle == null) { todayDayStyle = new TableItemStyle(); if (IsTrackingViewState) ((IStateManager)todayDayStyle).TrackViewState(); } return todayDayStyle; } } /// /// Gets or sets the value to use as today's date. /// [ Browsable(false), WebSysDescription(SR.Calendar_TodaysDate), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden) ] public DateTime TodaysDate { get { object o = ViewState["TodaysDate"]; return((o == null) ? DateTime.Today : (DateTime)o); } set { ViewState["TodaysDate"] = value.Date; } } [ DefaultValue(true), WebCategory("Accessibility"), WebSysDescription(SR.Table_UseAccessibleHeader) ] public virtual bool UseAccessibleHeader { get { object o = ViewState["UseAccessibleHeader"]; return (o != null) ? (bool)o : true; } set { ViewState["UseAccessibleHeader"] = value; } } /// /// Gets or sets the date that specifies what month to display. The date can be /// be any date within the month. /// [ Bindable(true), DefaultValue(typeof(DateTime), "1/1/0001"), WebSysDescription(SR.Calendar_VisibleDate) ] public DateTime VisibleDate { get { object o = ViewState["VisibleDate"]; return((o == null) ? DateTime.MinValue : (DateTime)o); } set { ViewState["VisibleDate"] = value.Date; } } /// /// Gets the style properties for the displaying weekend dates. This property is /// read-only. /// [ WebCategory("Styles"), WebSysDescription(SR.Calendar_WeekendDayStyle), DesignerSerializationVisibility(DesignerSerializationVisibility.Content), NotifyParentProperty(true), PersistenceMode(PersistenceMode.InnerProperty) ] public TableItemStyle WeekendDayStyle { get { if (weekendDayStyle == null) { weekendDayStyle = new TableItemStyle(); if (IsTrackingViewState) ((IStateManager)weekendDayStyle).TrackViewState(); } return weekendDayStyle; } } /// /// Occurs when each day is created in teh control hierarchy for the . /// [ WebCategory("Action"), WebSysDescription(SR.Calendar_OnDayRender) ] public event DayRenderEventHandler DayRender { add { Events.AddHandler(EventDayRender, value); } remove { Events.RemoveHandler(EventDayRender, value); } } /// /// Occurs when the user clicks on a day, week, or month /// selector and changes the . /// [ WebCategory("Action"), WebSysDescription(SR.Calendar_OnSelectionChanged) ] public event EventHandler SelectionChanged { add { Events.AddHandler(EventSelectionChanged, value); } remove { Events.RemoveHandler(EventSelectionChanged, value); } } /// /// Occurs when the /// user clicks on the next or previous month controls on the title. /// [ WebCategory("Action"), WebSysDescription(SR.Calendar_OnVisibleMonthChanged) ] public event MonthChangedEventHandler VisibleMonthChanged { add { Events.AddHandler(EventVisibleMonthChanged, value); } remove { Events.RemoveHandler(EventVisibleMonthChanged, value); } } // Methods /// /// private void ApplyTitleStyle(TableCell titleCell, Table titleTable, TableItemStyle titleStyle) { // apply affects that affect the whole background to the cell if (titleStyle.BackColor != Color.Empty) { titleCell.BackColor = titleStyle.BackColor; } if (titleStyle.BorderColor != Color.Empty) { titleCell.BorderColor = titleStyle.BorderColor; } if (titleStyle.BorderWidth != Unit.Empty) { titleCell.BorderWidth= titleStyle.BorderWidth; } if (titleStyle.BorderStyle != BorderStyle.NotSet) { titleCell.BorderStyle = titleStyle.BorderStyle; } if (titleStyle.Height != Unit.Empty) { titleCell.Height = titleStyle.Height; } if (titleStyle.VerticalAlign != VerticalAlign.NotSet) { titleCell.VerticalAlign = titleStyle.VerticalAlign; } // apply affects that affect everything else to the table if (titleStyle.CssClass.Length > 0) { titleTable.CssClass = titleStyle.CssClass; } else if (CssClass.Length > 0) { titleTable.CssClass = CssClass; } if (titleStyle.ForeColor != Color.Empty) { titleTable.ForeColor = titleStyle.ForeColor; } else if (ForeColor != Color.Empty) { titleTable.ForeColor = ForeColor; } titleTable.Font.CopyFrom(titleStyle.Font); titleTable.Font.MergeWith(this.Font); } /// /// /// protected override ControlCollection CreateControlCollection() { return new InternalControlCollection(this); } /// /// private DateTime EffectiveVisibleDate() { DateTime visDate = VisibleDate; if (visDate.Equals(DateTime.MinValue)) { visDate = TodaysDate; } // VSWhidbey 366243 if (IsMinSupportedYearMonth(visDate)) { return minSupportedDate; } else { return threadCalendar.AddDays(visDate, -(threadCalendar.GetDayOfMonth(visDate) - 1)); } } /// /// private DateTime FirstCalendarDay(DateTime visibleDate) { DateTime firstDayOfMonth = visibleDate; // VSWhidbey 366243 if (IsMinSupportedYearMonth(firstDayOfMonth)) { return firstDayOfMonth; } int daysFromLastMonth = ((int)threadCalendar.GetDayOfWeek(firstDayOfMonth)) - NumericFirstDayOfWeek(); // Always display at least one day from the previous month if (daysFromLastMonth <= 0) { daysFromLastMonth += 7; } return threadCalendar.AddDays(firstDayOfMonth, -daysFromLastMonth); } /// /// private string GetCalendarButtonText(string eventArgument, string buttonText, string title, bool showLink, Color foreColor) { if (showLink) { StringBuilder sb = new StringBuilder(); sb.Append(""); sb.Append(buttonText); sb.Append(""); return sb.ToString(); } else { return buttonText; } } /// /// private int GetDefinedStyleMask() { // Selected is always defined because it has default effects int styleMask = STYLEMASK_SELECTED; if (dayStyle != null && !dayStyle.IsEmpty) styleMask |= STYLEMASK_DAY; if (todayDayStyle != null && !todayDayStyle.IsEmpty) styleMask |= STYLEMASK_TODAY; if (otherMonthDayStyle != null && !otherMonthDayStyle.IsEmpty) styleMask |= STYLEMASK_OTHERMONTH; if (weekendDayStyle != null && !weekendDayStyle.IsEmpty) styleMask |= STYLEMASK_WEEKEND; return styleMask; } /// /// private string GetMonthName(int m, bool bFull) { if (bFull) { return DateTimeFormatInfo.CurrentInfo.GetMonthName(m); } else { return DateTimeFormatInfo.CurrentInfo.GetAbbreviatedMonthName(m); } } /// /// Determines if a /// contains week selectors. /// protected bool HasWeekSelectors(CalendarSelectionMode selectionMode) { return(selectionMode == CalendarSelectionMode.DayWeek || selectionMode == CalendarSelectionMode.DayWeekMonth); } private bool IsTheSameYearMonth(DateTime date1, DateTime date2) { #if DEBUG Debug.Assert(threadCalendarInitialized); #endif return (threadCalendar.GetEra(date1) == threadCalendar.GetEra(date2) && threadCalendar.GetYear(date1) == threadCalendar.GetYear(date2) && threadCalendar.GetMonth(date1) == threadCalendar.GetMonth(date2)); } private bool IsMinSupportedYearMonth(DateTime date) { #if DEBUG Debug.Assert(threadCalendarInitialized); #endif return IsTheSameYearMonth(minSupportedDate, date); } private bool IsMaxSupportedYearMonth(DateTime date) { #if DEBUG Debug.Assert(threadCalendarInitialized); #endif return IsTheSameYearMonth(maxSupportedDate, date); } /// /// /// Loads a saved state of the . /// protected override void LoadViewState(object savedState) { if (savedState != null) { object[] myState = (object[])savedState; if (myState[0] != null) base.LoadViewState(myState[0]); if (myState[1] != null) ((IStateManager)TitleStyle).LoadViewState(myState[1]); if (myState[2] != null) ((IStateManager)NextPrevStyle).LoadViewState(myState[2]); if (myState[3] != null) ((IStateManager)DayStyle).LoadViewState(myState[3]); if (myState[4] != null) ((IStateManager)DayHeaderStyle).LoadViewState(myState[4]); if (myState[5] != null) ((IStateManager)TodayDayStyle).LoadViewState(myState[5]); if (myState[6] != null) ((IStateManager)WeekendDayStyle).LoadViewState(myState[6]); if (myState[7] != null) ((IStateManager)OtherMonthDayStyle).LoadViewState(myState[7]); if (myState[8] != null) ((IStateManager)SelectedDayStyle).LoadViewState(myState[8]); if (myState[9] != null) ((IStateManager)SelectorStyle).LoadViewState(myState[9]); ArrayList selDates = (ArrayList)ViewState["SD"]; if (selDates != null) { dateList = selDates; selectedDates = null; // reset wrapper collection } } } /// /// /// Marks the starting point to begin tracking and saving changes to the /// control as part of the control viewstate. /// protected override void TrackViewState() { base.TrackViewState(); if (titleStyle != null) ((IStateManager)titleStyle).TrackViewState(); if (nextPrevStyle != null) ((IStateManager)nextPrevStyle).TrackViewState(); if (dayStyle != null) ((IStateManager)dayStyle).TrackViewState(); if (dayHeaderStyle != null) ((IStateManager)dayHeaderStyle).TrackViewState(); if (todayDayStyle != null) ((IStateManager)todayDayStyle).TrackViewState(); if (weekendDayStyle != null) ((IStateManager)weekendDayStyle).TrackViewState(); if (otherMonthDayStyle != null) ((IStateManager)otherMonthDayStyle).TrackViewState(); if (selectedDayStyle != null) ((IStateManager)selectedDayStyle).TrackViewState(); if (selectorStyle != null) ((IStateManager)selectorStyle).TrackViewState(); } /// /// private int NumericFirstDayOfWeek() { // Used globalized value by default return(FirstDayOfWeek == FirstDayOfWeek.Default) ? (int) DateTimeFormatInfo.CurrentInfo.FirstDayOfWeek : (int) FirstDayOfWeek; } /// /// Raises the event for a . /// protected virtual void OnDayRender(TableCell cell, CalendarDay day) { DayRenderEventHandler handler = (DayRenderEventHandler)Events[EventDayRender]; if (handler != null) { int absoluteDay = day.Date.Subtract(baseDate).Days; // VSWhidbey 215383: We return null for selectUrl if a control is not in // the page control tree. string selectUrl = null; Page page = Page; if (page != null) { string eventArgument = absoluteDay.ToString(CultureInfo.InvariantCulture); selectUrl = Page.ClientScript.GetPostBackClientHyperlink(this, eventArgument, true); } handler(this, new DayRenderEventArgs(cell, day, selectUrl)); } } /// /// Raises the event for a . /// protected virtual void OnSelectionChanged() { EventHandler handler = (EventHandler)Events[EventSelectionChanged]; if (handler != null) { handler(this, EventArgs.Empty); } } /// /// Raises the event for a . /// protected virtual void OnVisibleMonthChanged(DateTime newDate, DateTime previousDate) { MonthChangedEventHandler handler = (MonthChangedEventHandler)Events[EventVisibleMonthChanged]; if (handler != null) { handler(this, new MonthChangedEventArgs(newDate, previousDate)); } } /// /// /// Raises events on post back for the control. /// protected virtual void RaisePostBackEvent(string eventArgument) { ValidateEvent(UniqueID, eventArgument); if (AdapterInternal != null) { IPostBackEventHandler pbeh = AdapterInternal as IPostBackEventHandler; if (pbeh != null) { pbeh.RaisePostBackEvent(eventArgument); } } else { if (String.Compare(eventArgument, 0, NAVIGATE_MONTH_COMMAND, 0, NAVIGATE_MONTH_COMMAND.Length, StringComparison.Ordinal) == 0) { // Month navigation. The command starts with a "V" and the remainder is day difference from the // base date. DateTime oldDate = VisibleDate; if (oldDate.Equals(DateTime.MinValue)) { oldDate = TodaysDate; } int newDateDiff = Int32.Parse(eventArgument.Substring(NAVIGATE_MONTH_COMMAND.Length), CultureInfo.InvariantCulture); VisibleDate = baseDate.AddDays(newDateDiff); if (VisibleDate == DateTime.MinValue) { // MinValue would make the calendar shows today's month instead because it // is the default value of VisibleDate property, so we add a day to keep // showing the first supported month. // We assume the first supported month has more than one day. VisibleDate = DateTimeFormatInfo.CurrentInfo.Calendar.AddDays(VisibleDate, 1); } OnVisibleMonthChanged(VisibleDate, oldDate); } else if (String.Compare(eventArgument, 0, SELECT_RANGE_COMMAND, 0, SELECT_RANGE_COMMAND.Length, StringComparison.Ordinal) == 0) { // Range selection. The command starts with an "R". The remainder is an integer. When divided by 100 // the result is the day difference from the base date of the first day, and the remainder is the // number of days to select. int rangeValue = Int32.Parse(eventArgument.Substring(SELECT_RANGE_COMMAND.Length), CultureInfo.InvariantCulture); int dayDiff = rangeValue / 100; int dayRange = rangeValue % 100; if (dayRange < 1) { dayRange = 100 + dayRange; dayDiff -= 1; } DateTime dt = baseDate.AddDays(dayDiff); SelectRange(dt, dt.AddDays(dayRange - 1)); } else { // Single day selection. This is just a number which is the day difference from the base date. int dayDiff = Int32.Parse(eventArgument, CultureInfo.InvariantCulture); DateTime dt = baseDate.AddDays(dayDiff); SelectRange(dt, dt); } } } void IPostBackEventHandler.RaisePostBackEvent(string eventArgument) { RaisePostBackEvent(eventArgument); } /// protected internal override void OnPreRender(EventArgs e) { base.OnPreRender(e); if (Page != null) { Page.RegisterPostBackScript(); } } /// /// /// Displays the control on the client. /// protected internal override void Render(HtmlTextWriter writer) { threadCalendar = DateTimeFormatInfo.CurrentInfo.Calendar; minSupportedDate = threadCalendar.MinSupportedDateTime; maxSupportedDate = threadCalendar.MaxSupportedDateTime; #if DEBUG threadCalendarInitialized = true; #endif DateTime visibleDate = EffectiveVisibleDate(); DateTime firstDay = FirstCalendarDay(visibleDate); CalendarSelectionMode selectionMode = SelectionMode; // Make sure we are in a form tag with runat=server. if (Page != null) { Page.VerifyRenderingInServerForm(this); } // We only want to display the link if we have a page, or if we are on the design surface // If we can stops links being active on the Autoformat dialog, then we can remove this these checks. Page page = Page; bool buttonsActive; if (page == null || DesignMode) { buttonsActive = false; } else { buttonsActive = IsEnabled; } defaultForeColor = ForeColor; if (defaultForeColor == Color.Empty) { defaultForeColor = DefaultForeColor; } defaultButtonColorText = ColorTranslator.ToHtml(defaultForeColor); Table table = new Table(); if (ID != null) { table.ID = ClientID; } table.CopyBaseAttributes(this); if (ControlStyleCreated) { table.ApplyStyle(ControlStyle); } table.Width = Width; table.Height = Height; table.CellPadding = CellPadding; table.CellSpacing = CellSpacing; // default look if ((ControlStyleCreated == false) || (ControlStyle.IsSet(System.Web.UI.WebControls.Style.PROP_BORDERWIDTH) == false) || BorderWidth.Equals(Unit.Empty)) { table.BorderWidth = Unit.Pixel(1); } if (ShowGridLines) { table.GridLines = GridLines.Both; } else { table.GridLines = GridLines.None; } bool useAccessibleHeader = UseAccessibleHeader; if (useAccessibleHeader) { if (table.Attributes["title"] == null) { table.Attributes["title"] = SR.GetString(SR.Calendar_TitleText); } } string caption = Caption; if (caption.Length > 0) { table.Caption = caption; table.CaptionAlign = CaptionAlign; } table.RenderBeginTag(writer); if (ShowTitle) { RenderTitle(writer, visibleDate, selectionMode, buttonsActive, useAccessibleHeader); } if (ShowDayHeader) { RenderDayHeader(writer, visibleDate, selectionMode, buttonsActive, useAccessibleHeader); } RenderDays(writer, firstDay, visibleDate, selectionMode, buttonsActive, useAccessibleHeader); table.RenderEndTag(writer); } private void RenderCalendarCell(HtmlTextWriter writer, TableItemStyle style, string text, string title, bool hasButton, string eventArgument) { style.AddAttributesToRender(writer, this); writer.RenderBeginTag(HtmlTextWriterTag.Td); if (hasButton) { // render the button Color foreColor = style.ForeColor; writer.Write(""); writer.Write(text); writer.Write(""); } else { writer.Write(text); } writer.RenderEndTag(); } private void RenderCalendarHeaderCell(HtmlTextWriter writer, TableItemStyle style, string text, string abbrText) { style.AddAttributesToRender(writer, this); writer.AddAttribute("abbr", abbrText); writer.AddAttribute("scope", "col"); writer.RenderBeginTag(HtmlTextWriterTag.Th); writer.Write(text); writer.RenderEndTag(); } /// /// private void RenderDayHeader(HtmlTextWriter writer, DateTime visibleDate, CalendarSelectionMode selectionMode, bool buttonsActive, bool useAccessibleHeader) { writer.Write(ROWBEGINTAG); DateTimeFormatInfo dtf = DateTimeFormatInfo.CurrentInfo; if (HasWeekSelectors(selectionMode)) { TableItemStyle monthSelectorStyle = new TableItemStyle(); monthSelectorStyle.HorizontalAlign = HorizontalAlign.Center; // add the month selector button if required; if (selectionMode == CalendarSelectionMode.DayWeekMonth) { // Range selection. The command starts with an "R". The remainder is an integer. When divided by 100 // the result is the day difference from the base date of the first day, and the remainder is the // number of days to select. int startOffset = visibleDate.Subtract(baseDate).Days; int monthLength = threadCalendar.GetDaysInMonth(threadCalendar.GetYear(visibleDate), threadCalendar.GetMonth(visibleDate), threadCalendar.GetEra(visibleDate)); if (IsMinSupportedYearMonth(visibleDate)) { // The first supported month might not start with day 1 // (e.g. Sept 8 is the first supported date of JapaneseCalendar) monthLength = monthLength - threadCalendar.GetDayOfMonth(visibleDate) + 1; } else if (IsMaxSupportedYearMonth(visibleDate)) { // The last supported month might not have all days supported in that calendar month // (e.g. April 3 is the last supported date of HijriCalendar) monthLength = threadCalendar.GetDayOfMonth(maxSupportedDate); } string monthSelectKey = SELECT_RANGE_COMMAND + ((startOffset * 100) + monthLength).ToString(CultureInfo.InvariantCulture); monthSelectorStyle.CopyFrom(SelectorStyle); string selectMonthTitle = null; if (useAccessibleHeader) { selectMonthTitle = SR.GetString(SR.Calendar_SelectMonthTitle); } RenderCalendarCell(writer, monthSelectorStyle, SelectMonthText, selectMonthTitle, buttonsActive, monthSelectKey); } else { // otherwise make it look like the header row monthSelectorStyle.CopyFrom(DayHeaderStyle); RenderCalendarCell(writer, monthSelectorStyle, string.Empty, null, false, null); } } TableItemStyle dayNameStyle = new TableItemStyle(); dayNameStyle.HorizontalAlign = HorizontalAlign.Center; dayNameStyle.CopyFrom(DayHeaderStyle); DayNameFormat dayNameFormat = DayNameFormat; int numericFirstDay = NumericFirstDayOfWeek(); for (int i = numericFirstDay; i < numericFirstDay + 7; i++) { string dayName; int dayOfWeek = i % 7; switch (dayNameFormat) { case DayNameFormat.FirstLetter: dayName = dtf.GetDayName((DayOfWeek)dayOfWeek).Substring(0, 1); break; case DayNameFormat.FirstTwoLetters: dayName = dtf.GetDayName((DayOfWeek)dayOfWeek).Substring(0, 2); break; case DayNameFormat.Full: dayName = dtf.GetDayName((DayOfWeek)dayOfWeek); break; case DayNameFormat.Short: dayName = dtf.GetAbbreviatedDayName((DayOfWeek)dayOfWeek); break; case DayNameFormat.Shortest: dayName = dtf.GetShortestDayName((DayOfWeek)dayOfWeek); break; default: Debug.Assert(false, "Unknown DayNameFormat value!"); goto case DayNameFormat.Short; } if (useAccessibleHeader) { string fullDayName = dtf.GetDayName((DayOfWeek)dayOfWeek); RenderCalendarHeaderCell(writer, dayNameStyle, dayName, fullDayName); } else { RenderCalendarCell(writer, dayNameStyle, dayName, null, false, null); } } writer.Write(ROWENDTAG); } /// /// private void RenderDays(HtmlTextWriter writer, DateTime firstDay, DateTime visibleDate, CalendarSelectionMode selectionMode, bool buttonsActive, bool useAccessibleHeader) { // Now add the rows for the actual days DateTime d = firstDay; TableItemStyle weekSelectorStyle = null; Unit defaultWidth; bool hasWeekSelectors = HasWeekSelectors(selectionMode); if (hasWeekSelectors) { weekSelectorStyle = new TableItemStyle(); weekSelectorStyle.Width = Unit.Percentage(12); weekSelectorStyle.HorizontalAlign = HorizontalAlign.Center; weekSelectorStyle.CopyFrom(SelectorStyle); defaultWidth = Unit.Percentage(12); } else { defaultWidth = Unit.Percentage(14); } // This determines whether we need to call DateTime.ToString for each day. The only culture/calendar // that requires this for now is the HebrewCalendar. bool usesStandardDayDigits = !(threadCalendar is HebrewCalendar); // This determines whether we can write out cells directly, or whether we have to create whole // TableCell objects for each day. bool hasRenderEvent = (this.GetType() != typeof(Calendar) || Events[EventDayRender] != null); TableItemStyle [] cellStyles = new TableItemStyle[16]; int definedStyleMask = GetDefinedStyleMask(); DateTime todaysDate = TodaysDate; string selectWeekText = SelectWeekText; bool daysSelectable = buttonsActive && (selectionMode != CalendarSelectionMode.None); int visibleDateMonth = threadCalendar.GetMonth(visibleDate); int absoluteDay = firstDay.Subtract(baseDate).Days; // VSWhidbey 480155: flag to indicate if forecolor needs to be set // explicitly in design mode to mimic runtime rendering with the // limitation of not supporting CSS class color setting. bool inDesignSelectionMode = (DesignMode && SelectionMode != CalendarSelectionMode.None); //------------------------------------------------------------------ // VSWhidbey 366243: The following variables are for boundary cases // such as the current visible month is the first or the last // supported month. They are used in the 'for' loops below. // For the first supported month, calculate how many days to // skip at the beginning of the first month. E.g. JapaneseCalendar // starts at Sept 8. int numOfFirstDaysToSkip = 0; if (IsMinSupportedYearMonth(visibleDate)) { numOfFirstDaysToSkip = (int)threadCalendar.GetDayOfWeek(firstDay) - NumericFirstDayOfWeek(); // If negative, it simply means the the index of the starting // day name is greater than the day name of the first supported // date. We add back 7 to get the number of days to skip. if (numOfFirstDaysToSkip < 0) { numOfFirstDaysToSkip += 7; } } Debug.Assert(numOfFirstDaysToSkip < 7); // For the last or second last supported month, initialize variables // to identify the last supported date of the current calendar. // e.g. The last supported date of HijriCalendar is April 3. When // the second last monthh is shown, it can be the case that not all // cells will be filled up. bool passedLastSupportedDate = false; DateTime secondLastMonth = threadCalendar.AddMonths(maxSupportedDate, -1); bool lastOrSecondLastMonth = (IsMaxSupportedYearMonth(visibleDate) || IsTheSameYearMonth(secondLastMonth, visibleDate)); //------------------------------------------------------------------ for (int iRow = 0; iRow < 6; iRow++) { if (passedLastSupportedDate) { break; } writer.Write(ROWBEGINTAG); // add week selector column and button if required if (hasWeekSelectors) { // Range selection. The command starts with an "R". The remainder is an integer. When divided by 100 // the result is the day difference from the base date of the first day, and the remainder is the // number of days to select. int dayDiffParameter = (absoluteDay * 100) + 7; // Adjust the dayDiff for the first or the last supported month if (numOfFirstDaysToSkip > 0) { dayDiffParameter -= numOfFirstDaysToSkip; } else if (lastOrSecondLastMonth) { int daysFromLastDate = maxSupportedDate.Subtract(d).Days; if (daysFromLastDate < 6) { dayDiffParameter -= (6 - daysFromLastDate); } } string weekSelectKey = SELECT_RANGE_COMMAND + dayDiffParameter.ToString(CultureInfo.InvariantCulture); string selectWeekTitle = null; if (useAccessibleHeader) { int weekOfMonth = iRow + 1; selectWeekTitle = SR.GetString(SR.Calendar_SelectWeekTitle, weekOfMonth.ToString(CultureInfo.InvariantCulture)); } RenderCalendarCell(writer, weekSelectorStyle, selectWeekText, selectWeekTitle, buttonsActive, weekSelectKey); } for (int iDay = 0; iDay < 7; iDay++) { // Render empty cells for special cases to handle the first // or last supported month. if (numOfFirstDaysToSkip > 0) { iDay += numOfFirstDaysToSkip; for ( ; numOfFirstDaysToSkip > 0; numOfFirstDaysToSkip--) { writer.RenderBeginTag(HtmlTextWriterTag.Td); writer.RenderEndTag(); } } else if (passedLastSupportedDate) { for ( ; iDay < 7; iDay++) { writer.RenderBeginTag(HtmlTextWriterTag.Td); writer.RenderEndTag(); } break; } int dayOfWeek = (int)threadCalendar.GetDayOfWeek(d); int dayOfMonth = threadCalendar.GetDayOfMonth(d); string dayNumberText; if ((dayOfMonth <= cachedNumberMax) && usesStandardDayDigits) { dayNumberText = cachedNumbers[dayOfMonth]; } else { dayNumberText = d.ToString("dd", CultureInfo.CurrentCulture); } CalendarDay day = new CalendarDay(d, (dayOfWeek == 0 || dayOfWeek == 6), // IsWeekend d.Equals(todaysDate), // IsToday (selectedDates != null) && selectedDates.Contains(d), // IsSelected threadCalendar.GetMonth(d) != visibleDateMonth, // IsOtherMonth dayNumberText // Number Text ); int styleMask = STYLEMASK_DAY; if (day.IsSelected) styleMask |= STYLEMASK_SELECTED; if (day.IsOtherMonth) styleMask |= STYLEMASK_OTHERMONTH; if (day.IsToday) styleMask |= STYLEMASK_TODAY; if (day.IsWeekend) styleMask |= STYLEMASK_WEEKEND; int dayStyleMask = definedStyleMask & styleMask; // determine the unique portion of the mask for the current calendar, // which will strip out the day style bit int dayStyleID = dayStyleMask & STYLEMASK_UNIQUE; TableItemStyle cellStyle = cellStyles[dayStyleID]; if (cellStyle == null) { cellStyle = new TableItemStyle(); SetDayStyles(cellStyle, dayStyleMask, defaultWidth); cellStyles[dayStyleID] = cellStyle; } string dayTitle = null; if (useAccessibleHeader) { dayTitle = d.ToString("m", CultureInfo.CurrentCulture); } if (hasRenderEvent) { TableCell cdc = new TableCell(); cdc.ApplyStyle(cellStyle); LiteralControl dayContent = new LiteralControl(dayNumberText); cdc.Controls.Add(dayContent); day.IsSelectable = daysSelectable; OnDayRender(cdc, day); // refresh the day content dayContent.Text = GetCalendarButtonText(absoluteDay.ToString(CultureInfo.InvariantCulture), dayNumberText, dayTitle, buttonsActive && day.IsSelectable, cdc.ForeColor); cdc.RenderControl(writer); } else { // VSWhidbey 480155: In design mode we render days as // texts instead of links so CSS class color setting is // supported. But this differs in runtime rendering // where CSS class color setting is not supported. To // correctly mimic the forecolor of runtime rendering in // design time, the default color, which is used in // runtime rendering, is explicitly set in this case. if (inDesignSelectionMode && cellStyle.ForeColor.IsEmpty) { cellStyle.ForeColor = defaultForeColor; } RenderCalendarCell(writer, cellStyle, dayNumberText, dayTitle, daysSelectable, absoluteDay.ToString(CultureInfo.InvariantCulture)); } Debug.Assert(!passedLastSupportedDate); if (lastOrSecondLastMonth && d.Month == maxSupportedDate.Month && d.Day == maxSupportedDate.Day) { passedLastSupportedDate = true; } else { d = threadCalendar.AddDays(d, 1); absoluteDay++; } } writer.Write(ROWENDTAG); } } /// /// private void RenderTitle(HtmlTextWriter writer, DateTime visibleDate, CalendarSelectionMode selectionMode, bool buttonsActive, bool useAccessibleHeader) { writer.Write(ROWBEGINTAG); TableCell titleCell = new TableCell(); Table titleTable = new Table(); // default title table/cell styles titleCell.ColumnSpan = HasWeekSelectors(selectionMode) ? 8 : 7; titleCell.BackColor = Color.Silver; titleTable.GridLines = GridLines.None; titleTable.Width = Unit.Percentage(100); titleTable.CellSpacing = 0; TableItemStyle titleStyle = TitleStyle; ApplyTitleStyle(titleCell, titleTable, titleStyle); titleCell.RenderBeginTag(writer); titleTable.RenderBeginTag(writer); writer.Write(ROWBEGINTAG); NextPrevFormat nextPrevFormat = NextPrevFormat; TableItemStyle nextPrevStyle = new TableItemStyle(); nextPrevStyle.Width = Unit.Percentage(15); nextPrevStyle.CopyFrom(NextPrevStyle); if (ShowNextPrevMonth) { if (IsMinSupportedYearMonth(visibleDate)) { writer.RenderBeginTag(HtmlTextWriterTag.Td); writer.RenderEndTag(); } else { string prevMonthText; if (nextPrevFormat == NextPrevFormat.ShortMonth || nextPrevFormat == NextPrevFormat.FullMonth) { int monthNo = threadCalendar.GetMonth(threadCalendar.AddMonths(visibleDate, - 1)); prevMonthText = GetMonthName(monthNo, (nextPrevFormat == NextPrevFormat.FullMonth)); } else { prevMonthText = PrevMonthText; } // Month navigation. The command starts with a "V" and the remainder is day difference from the // base date. DateTime prevMonthDate; // VSWhidbey 366243: Some calendar's min supported date is // not the first day of the month (e.g. JapaneseCalendar. // So if we are setting the second supported month, the prev // month link should always point to the first supported // date instead of the first day of the previous month. DateTime secondSupportedMonth = threadCalendar.AddMonths(minSupportedDate, 1); if (IsTheSameYearMonth(secondSupportedMonth, visibleDate)) { prevMonthDate = minSupportedDate; } else { prevMonthDate = threadCalendar.AddMonths(visibleDate, -1); } string prevMonthKey = NAVIGATE_MONTH_COMMAND + (prevMonthDate.Subtract(baseDate)).Days.ToString(CultureInfo.InvariantCulture); string previousMonthTitle = null; if (useAccessibleHeader) { previousMonthTitle = SR.GetString(SR.Calendar_PreviousMonthTitle); } RenderCalendarCell(writer, nextPrevStyle, prevMonthText, previousMonthTitle, buttonsActive, prevMonthKey); } } TableItemStyle cellMainStyle = new TableItemStyle(); if (titleStyle.HorizontalAlign != HorizontalAlign.NotSet) { cellMainStyle.HorizontalAlign = titleStyle.HorizontalAlign; } else { cellMainStyle.HorizontalAlign = HorizontalAlign.Center; } cellMainStyle.Wrap = titleStyle.Wrap; cellMainStyle.Width = Unit.Percentage(70); string titleText; switch (TitleFormat) { case TitleFormat.Month: titleText = visibleDate.ToString("MMMM", CultureInfo.CurrentCulture); break; case TitleFormat.MonthYear: string titlePattern = DateTimeFormatInfo.CurrentInfo.YearMonthPattern; // Some cultures have a comma in their YearMonthPattern, which does not look // right in a calendar. Use a fixed pattern for those. if (titlePattern.IndexOf(',') >= 0) { titlePattern = "MMMM yyyy"; } titleText = visibleDate.ToString(titlePattern, CultureInfo.CurrentCulture); break; default: Debug.Assert(false, "Unknown TitleFormat value!"); goto case TitleFormat.MonthYear; } RenderCalendarCell(writer, cellMainStyle, titleText, null, false, null); if (ShowNextPrevMonth) { if (IsMaxSupportedYearMonth(visibleDate)) { writer.RenderBeginTag(HtmlTextWriterTag.Td); writer.RenderEndTag(); } else { // Style for this one is identical bar nextPrevStyle.HorizontalAlign = HorizontalAlign.Right; string nextMonthText; if (nextPrevFormat == NextPrevFormat.ShortMonth || nextPrevFormat == NextPrevFormat.FullMonth) { int monthNo = threadCalendar.GetMonth(threadCalendar.AddMonths(visibleDate, 1)); nextMonthText = GetMonthName(monthNo, (nextPrevFormat == NextPrevFormat.FullMonth)); } else { nextMonthText = NextMonthText; } // Month navigation. The command starts with a "V" and the remainder is day difference from the // base date. DateTime nextMonthDate = threadCalendar.AddMonths(visibleDate, 1); string nextMonthKey = NAVIGATE_MONTH_COMMAND + (nextMonthDate.Subtract(baseDate)).Days.ToString(CultureInfo.InvariantCulture); string nextMonthTitle = null; if (useAccessibleHeader) { nextMonthTitle = SR.GetString(SR.Calendar_NextMonthTitle); } RenderCalendarCell(writer, nextPrevStyle, nextMonthText, nextMonthTitle, buttonsActive, nextMonthKey); } } writer.Write(ROWENDTAG); titleTable.RenderEndTag(writer); titleCell.RenderEndTag(writer); writer.Write(ROWENDTAG); } /// /// /// Stores the state of the System.Web.UI.WebControls.Calender. /// protected override object SaveViewState() { if (SelectedDates.Count > 0) ViewState["SD"] = dateList; object[] myState = new object[10]; myState[0] = base.SaveViewState(); myState[1] = (titleStyle != null) ? ((IStateManager)titleStyle).SaveViewState() : null; myState[2] = (nextPrevStyle != null) ? ((IStateManager)nextPrevStyle).SaveViewState() : null; myState[3] = (dayStyle != null) ? ((IStateManager)dayStyle).SaveViewState() : null; myState[4] = (dayHeaderStyle != null) ? ((IStateManager)dayHeaderStyle).SaveViewState() : null; myState[5] = (todayDayStyle != null) ? ((IStateManager)todayDayStyle).SaveViewState() : null; myState[6] = (weekendDayStyle != null) ? ((IStateManager)weekendDayStyle).SaveViewState() : null; myState[7] = (otherMonthDayStyle != null) ? ((IStateManager)otherMonthDayStyle).SaveViewState() : null; myState[8] = (selectedDayStyle != null) ? ((IStateManager)selectedDayStyle).SaveViewState() : null; myState[9] = (selectorStyle != null) ? ((IStateManager)selectorStyle).SaveViewState() : null; for (int i = 0; i /// private void SetDayStyles(TableItemStyle style, int styleMask, Unit defaultWidth) { // default day styles style.Width = defaultWidth; style.HorizontalAlign = HorizontalAlign.Center; if ((styleMask & STYLEMASK_DAY) != 0) { style.CopyFrom(DayStyle); } if ((styleMask & STYLEMASK_WEEKEND) != 0) { style.CopyFrom(WeekendDayStyle); } if ((styleMask & STYLEMASK_OTHERMONTH) != 0) { style.CopyFrom(OtherMonthDayStyle); } if ((styleMask & STYLEMASK_TODAY) != 0) { style.CopyFrom(TodayDayStyle); } if ((styleMask & STYLEMASK_SELECTED) != 0) { // default selected day style style.ForeColor = Color.White; style.BackColor = Color.Silver; style.CopyFrom(SelectedDayStyle); } } } }