Merge pull request #3213 from henricm/fix-for-win-securestring-to-bstr
[mono.git] / mcs / class / referencesource / System.Web / UI / WebControls / Calendar.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="Calendar.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 //------------------------------------------------------------------------------
6
7 namespace System.Web.UI.WebControls {
8     using System.Threading;
9     using System.Globalization;
10     using System.ComponentModel;
11     using System;
12     using System.Web;
13     using System.Web.UI;
14     using System.Web.Util;
15     using System.Collections;
16     using System.ComponentModel.Design;
17     using System.Drawing;
18     using System.Text;
19
20     using System.IO;
21     using System.Reflection;
22
23
24
25     /// <devdoc>
26     ///    <para>Displays a one-month calendar and allows the user to
27     ///       view and select a specific day, week, or month.</para>
28     /// </devdoc>
29     [
30     ControlValueProperty("SelectedDate", typeof(DateTime), "1/1/0001"),
31     DataBindingHandler("System.Web.UI.Design.WebControls.CalendarDataBindingHandler, " + AssemblyRef.SystemDesign),
32     DefaultEvent("SelectionChanged"),
33     DefaultProperty("SelectedDate"),
34     Designer("System.Web.UI.Design.WebControls.CalendarDesigner, " + AssemblyRef.SystemDesign),
35     SupportsEventValidation
36     ]
37     public class Calendar : WebControl, IPostBackEventHandler {
38
39         private static readonly object EventDayRender = new object();
40         private static readonly object EventSelectionChanged = new object();
41         private static readonly object EventVisibleMonthChanged = new object();
42
43         private TableItemStyle titleStyle;
44         private TableItemStyle nextPrevStyle;
45         private TableItemStyle dayHeaderStyle;
46         private TableItemStyle selectorStyle;
47         private TableItemStyle dayStyle;
48         private TableItemStyle otherMonthDayStyle;
49         private TableItemStyle todayDayStyle;
50         private TableItemStyle selectedDayStyle;
51         private TableItemStyle weekendDayStyle;
52         private string defaultButtonColorText;
53
54         private static readonly Color DefaultForeColor = Color.Black;
55         private Color defaultForeColor;
56
57         private ArrayList dateList;
58         private SelectedDatesCollection selectedDates;
59         private System.Globalization.Calendar threadCalendar;
60         private DateTime minSupportedDate;
61         private DateTime maxSupportedDate;
62 #if DEBUG
63         private bool threadCalendarInitialized;
64 #endif
65
66         private const string SELECT_RANGE_COMMAND = "R";
67         private const string NAVIGATE_MONTH_COMMAND = "V";
68
69         private static DateTime baseDate = new DateTime(2000, 1, 1);
70
71         private const int STYLEMASK_DAY = 16;
72         private const int STYLEMASK_UNIQUE = 15;
73         private const int STYLEMASK_SELECTED = 8;
74         private const int STYLEMASK_TODAY = 4;
75         private const int STYLEMASK_OTHERMONTH = 2;
76         private const int STYLEMASK_WEEKEND = 1;
77         private const string ROWBEGINTAG = "<tr>";
78         private const string ROWENDTAG = "</tr>";
79
80         // Cache commonly used strings. This improves performance and memory usage.
81         private const int cachedNumberMax = 31;
82         private static readonly string[] cachedNumbers = new string [] {
83                   "0",  "1",   "2",   "3",   "4",   "5",   "6",
84                   "7",  "8",   "9",  "10",  "11",  "12",  "13",
85                  "14", "15",  "16",  "17",  "18",  "19",  "20",
86                  "21", "22",  "23",  "24",  "25",  "26",  "27",
87                  "28", "29",  "30",  "31",
88         };
89
90
91         /// <devdoc>
92         /// <para>Initializes a new instance of the <see cref='System.Web.UI.WebControls.Calendar'/> class.</para>
93         /// </devdoc>
94         public Calendar() : base(HtmlTextWriterTag.Table) {
95         }
96
97
98         [
99         Localizable(true),
100         DefaultValue(""),
101         WebCategory("Accessibility"),
102         WebSysDescription(SR.Calendar_Caption)
103         ]
104         public virtual string Caption {
105             get {
106                 string s = (string)ViewState["Caption"];
107                 return (s != null) ? s : String.Empty;
108             }
109             set {
110                 ViewState["Caption"] = value;
111             }
112         }
113
114
115         [
116         DefaultValue(TableCaptionAlign.NotSet),
117         WebCategory("Accessibility"),
118         WebSysDescription(SR.WebControl_CaptionAlign)
119         ]
120         public virtual TableCaptionAlign CaptionAlign {
121             get {
122                 object o = ViewState["CaptionAlign"];
123                 return (o != null) ? (TableCaptionAlign)o : TableCaptionAlign.NotSet;
124             }
125             set {
126                 if ((value < TableCaptionAlign.NotSet) ||
127                     (value > TableCaptionAlign.Right)) {
128                     throw new ArgumentOutOfRangeException("value");
129                 }
130                 ViewState["CaptionAlign"] = value;
131             }
132         }
133
134
135         /// <devdoc>
136         ///    <para>Gets or sets the amount of space between cells.</para>
137         /// </devdoc>
138         [
139         WebCategory("Layout"),
140         DefaultValue(2),
141         WebSysDescription(SR.Calendar_CellPadding)
142         ]
143         public int CellPadding {
144             get {
145                 object o = ViewState["CellPadding"];
146                 return((o == null) ? 2 : (int)o);
147             }
148             set {
149                 if (value < - 1 ) {
150                     throw new ArgumentOutOfRangeException("value");
151                 }
152                 ViewState["CellPadding"] = value;
153             }
154         }
155
156
157         /// <devdoc>
158         ///    <para>Gets or sets the amount of space between the contents of a cell
159         ///       and the cell's border.</para>
160         /// </devdoc>
161         [
162         WebCategory("Layout"),
163         DefaultValue(0),
164         WebSysDescription(SR.Calendar_CellSpacing)
165         ]
166         public int CellSpacing {
167             get {
168                 object o = ViewState["CellSpacing"];
169                 return((o == null) ?  0 : (int)o);
170             }
171             set {
172                 if (value < -1 ) {
173                     throw new ArgumentOutOfRangeException("value");
174                 }
175                 ViewState["CellSpacing"] = (int)value;
176             }
177         }
178
179
180         /// <devdoc>
181         ///    <para> Gets the style property of the day-of-the-week header. This property is read-only.</para>
182         /// </devdoc>
183         [
184         WebCategory("Styles"),
185         WebSysDescription(SR.Calendar_DayHeaderStyle),
186         DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
187         NotifyParentProperty(true),
188         PersistenceMode(PersistenceMode.InnerProperty)
189         ]
190         public TableItemStyle DayHeaderStyle {
191             get {
192                 if (dayHeaderStyle == null) {
193                     dayHeaderStyle = new TableItemStyle();
194                     if (IsTrackingViewState)
195                         ((IStateManager)dayHeaderStyle).TrackViewState();
196                 }
197                 return dayHeaderStyle;
198             }
199         }
200
201
202         /// <devdoc>
203         ///    <para>Gets or sets
204         ///       the format for the names of days.</para>
205         /// </devdoc>
206         [
207         WebCategory("Appearance"),
208         DefaultValue(DayNameFormat.Short),
209         WebSysDescription(SR.Calendar_DayNameFormat)
210         ]
211         public DayNameFormat DayNameFormat {
212             get {
213                 object dnf = ViewState["DayNameFormat"];
214                 return((dnf == null) ? DayNameFormat.Short : (DayNameFormat)dnf);
215             }
216             set {
217                 if (value < DayNameFormat.Full || value > DayNameFormat.Shortest) {
218                     throw new ArgumentOutOfRangeException("value");
219                 }
220                 ViewState["DayNameFormat"] = value;
221             }
222         }
223
224
225         /// <devdoc>
226         ///    <para> Gets the style properties for the days. This property is read-only.</para>
227         /// </devdoc>
228         [
229         WebCategory("Styles"),
230         DefaultValue(null),
231         WebSysDescription(SR.Calendar_DayStyle),
232         DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
233         NotifyParentProperty(true),
234         PersistenceMode(PersistenceMode.InnerProperty)
235         ]
236         public TableItemStyle DayStyle {
237             get {
238                 if (dayStyle == null) {
239                     dayStyle = new TableItemStyle();
240                     if (IsTrackingViewState)
241                         ((IStateManager)dayStyle).TrackViewState();
242                 }
243                 return dayStyle;
244             }
245         }
246
247
248         /// <devdoc>
249         ///    <para> Gets
250         ///       or sets the day of the week to display in the calendar's first
251         ///       column.</para>
252         /// </devdoc>
253         [
254         WebCategory("Appearance"),
255         DefaultValue(FirstDayOfWeek.Default),
256         WebSysDescription(SR.Calendar_FirstDayOfWeek)
257         ]
258         public FirstDayOfWeek FirstDayOfWeek {
259             get {
260                 object o = ViewState["FirstDayOfWeek"];
261                 return((o == null) ? FirstDayOfWeek.Default : (FirstDayOfWeek)o);
262             }
263             set {
264                 if (value < FirstDayOfWeek.Sunday || value > FirstDayOfWeek.Default) {
265                     throw new ArgumentOutOfRangeException("value");
266                 }
267
268                 ViewState["FirstDayOfWeek"] = value;
269             }
270         }
271
272
273         /// <devdoc>
274         ///    <para>Gets or sets the text shown for the next month
275         ///       navigation hyperlink if the <see cref='System.Web.UI.WebControls.Calendar.ShowNextPrevMonth'/> property is set to
276         ///    <see langword='true'/>.</para>
277         /// </devdoc>
278         [
279         Localizable(true),
280         WebCategory("Appearance"),
281         DefaultValue("&gt;"),
282         WebSysDescription(SR.Calendar_NextMonthText)
283         ]
284         public string NextMonthText {
285             get {
286                 object s = ViewState["NextMonthText"];
287                 return((s == null) ? "&gt;" : (String) s);
288             }
289             set {
290                 ViewState["NextMonthText"] = value;
291             }
292         }
293
294
295         /// <devdoc>
296         ///    <para>Gets or sets the format of the next and previous month hyperlinks in the
297         ///       title.</para>
298         /// </devdoc>
299         [
300         WebCategory("Appearance"),
301         DefaultValue(NextPrevFormat.CustomText),
302         WebSysDescription(SR.Calendar_NextPrevFormat)
303         ]
304         public NextPrevFormat NextPrevFormat {
305             get {
306                 object npf = ViewState["NextPrevFormat"];
307                 return((npf == null) ? NextPrevFormat.CustomText : (NextPrevFormat)npf);
308             }
309             set {
310                 if (value < NextPrevFormat.CustomText || value > NextPrevFormat.FullMonth) {
311                     throw new ArgumentOutOfRangeException("value");
312                 }
313                 ViewState["NextPrevFormat"] = value;
314             }
315         }
316
317
318         /// <devdoc>
319         ///    <para> Gets the style properties for the next/previous month navigators. This property is
320         ///       read-only.</para>
321         /// </devdoc>
322         [
323         WebCategory("Styles"),
324         WebSysDescription(SR.Calendar_NextPrevStyle),
325         DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
326         NotifyParentProperty(true),
327         PersistenceMode(PersistenceMode.InnerProperty)
328         ]
329         public TableItemStyle NextPrevStyle {
330             get {
331                 if (nextPrevStyle == null) {
332                     nextPrevStyle = new TableItemStyle();
333                     if (IsTrackingViewState)
334                         ((IStateManager)nextPrevStyle).TrackViewState();
335                 }
336                 return nextPrevStyle;
337             }
338         }
339
340
341
342         /// <devdoc>
343         ///    <para>Gets the style properties for the days from the months preceding and following the current month.
344         ///       This property is read-only.</para>
345         /// </devdoc>
346         [
347         WebCategory("Styles"),
348         DefaultValue(null),
349         WebSysDescription(SR.Calendar_OtherMonthDayStyle),
350         DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
351         NotifyParentProperty(true),
352         PersistenceMode(PersistenceMode.InnerProperty)
353         ]
354         public TableItemStyle OtherMonthDayStyle {
355             get {
356                 if (otherMonthDayStyle == null) {
357                     otherMonthDayStyle = new TableItemStyle();
358                     if (IsTrackingViewState)
359                         ((IStateManager)otherMonthDayStyle).TrackViewState();
360
361                 }
362                 return otherMonthDayStyle;
363             }
364         }
365
366
367         /// <devdoc>
368         ///    <para>Gets or sets the text shown for the previous month
369         ///       navigation hyperlink if the <see cref='System.Web.UI.WebControls.Calendar.ShowNextPrevMonth'/> property is set to
370         ///    <see langword='true'/>
371         ///    .</para>
372         /// </devdoc>
373         [
374         Localizable(true),
375         WebCategory("Appearance"),
376         DefaultValue("&lt;"),
377         WebSysDescription(SR.Calendar_PrevMonthText)
378         ]
379         public string PrevMonthText {
380             get {
381                 object s = ViewState["PrevMonthText"];
382                 return((s == null) ? "&lt;" : (String) s);
383             }
384             set {
385                 ViewState["PrevMonthText"] = value;
386             }
387         }
388
389         public override bool SupportsDisabledAttribute {
390             get {
391                 return RenderingCompatibility < VersionUtil.Framework40;
392             }
393         }
394
395         /// <devdoc>
396         ///    <para>Gets or sets the date that is currently selected
397         ///       date.</para>
398         /// </devdoc>
399         [
400         Bindable(true, BindingDirection.TwoWay),
401         DefaultValue(typeof(DateTime), "1/1/0001"),
402         WebSysDescription(SR.Calendar_SelectedDate)
403         ]
404         public DateTime SelectedDate {
405             get {
406                 if (SelectedDates.Count == 0) {
407                     return DateTime.MinValue;
408                 }
409                 return SelectedDates[0];
410             }
411             set {
412                 if (value == DateTime.MinValue) {
413                     SelectedDates.Clear();
414                 }
415                 else {
416                     SelectedDates.SelectRange(value, value);
417                 }
418             }
419         }
420
421
422         /// <devdoc>
423         /// <para>Gets a collection of <see cref='System.DateTime' qualify='true'/> objects representing days selected on the <see cref='System.Web.UI.WebControls.Calendar'/>. This
424         ///    property is read-only.</para>
425         /// </devdoc>
426         [
427         Browsable(false),
428         WebSysDescription(SR.Calendar_SelectedDates),
429         DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
430         ]
431         public SelectedDatesCollection SelectedDates {
432             get {
433                 if (selectedDates == null) {
434                     if (dateList == null) {
435                         dateList = new ArrayList();
436                     }
437                     selectedDates = new SelectedDatesCollection(dateList);
438                 }
439                 return selectedDates;
440             }
441         }
442
443
444         /// <devdoc>
445         ///    <para>Gets the style properties for the selected date. This property is read-only.</para>
446         /// </devdoc>
447         [
448         WebCategory("Styles"),
449         DefaultValue(null),
450         WebSysDescription(SR.Calendar_SelectedDayStyle),
451         DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
452         NotifyParentProperty(true),
453         PersistenceMode(PersistenceMode.InnerProperty)
454         ]
455         public TableItemStyle SelectedDayStyle {
456             get {
457                 if (selectedDayStyle == null) {
458                     selectedDayStyle = new TableItemStyle();
459                     if (IsTrackingViewState)
460                         ((IStateManager)selectedDayStyle).TrackViewState();
461                 }
462                 return selectedDayStyle;
463             }
464         }
465
466
467         /// <devdoc>
468         ///    <para>Gets or sets the date selection capabilities on the
469         ///    <see cref='System.Web.UI.WebControls.Calendar'/>
470         ///    to allow the user to select a day, week, or month.</para>
471         /// </devdoc>
472         [
473         WebCategory("Behavior"),
474         DefaultValue(CalendarSelectionMode.Day),
475         WebSysDescription(SR.Calendar_SelectionMode)
476         ]
477         public CalendarSelectionMode SelectionMode {
478             get {
479                 object csm = ViewState["SelectionMode"];
480                 return((csm == null) ? CalendarSelectionMode.Day : (CalendarSelectionMode)csm);
481             }
482             set {
483                 if (value < CalendarSelectionMode.None || value > CalendarSelectionMode.DayWeekMonth) {
484                     throw new ArgumentOutOfRangeException("value");
485                 }
486                 ViewState["SelectionMode"] = value;
487             }
488         }
489
490
491         /// <devdoc>
492         ///    <para>Gets or sets the text shown for the month selection in
493         ///       the selector column if <see cref='System.Web.UI.WebControls.Calendar.SelectionMode'/> is
494         ///    <see langword='CalendarSelectionMode.DayWeekMonth'/>.</para>
495         /// </devdoc>
496         [
497         Localizable(true),
498         WebCategory("Appearance"),
499         DefaultValue("&gt;&gt;"),
500         WebSysDescription(SR.Calendar_SelectMonthText)
501         ]
502         public string SelectMonthText {
503             get {
504                 object s = ViewState["SelectMonthText"];
505                 return((s == null) ? "&gt;&gt;" : (String) s);
506             }
507             set {
508                 ViewState["SelectMonthText"] = value;
509             }
510         }
511
512
513         /// <devdoc>
514         ///    <para> Gets the style properties for the week and month selectors. This property is read-only.</para>
515         /// </devdoc>
516         [
517         WebCategory("Styles"),
518         WebSysDescription(SR.Calendar_SelectorStyle),
519         DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
520         NotifyParentProperty(true),
521         PersistenceMode(PersistenceMode.InnerProperty)
522         ]
523         public TableItemStyle SelectorStyle {
524             get {
525                 if (selectorStyle == null) {
526                     selectorStyle = new TableItemStyle();
527                     if (IsTrackingViewState)
528                         ((IStateManager)selectorStyle).TrackViewState();
529                 }
530                 return selectorStyle;
531             }
532         }
533
534         /// <devdoc>
535         ///    <para>Gets or sets the text shown for the week selection in
536         ///       the selector column if <see cref='System.Web.UI.WebControls.Calendar.SelectionMode'/> is
537         ///    <see langword='CalendarSelectionMode.DayWeek '/>or
538         ///    <see langword='CalendarSelectionMode.DayWeekMonth'/>.</para>
539         /// </devdoc>
540         [
541         Localizable(true),
542         WebCategory("Appearance"),
543         DefaultValue("&gt;"),
544         WebSysDescription(SR.Calendar_SelectWeekText)
545         ]
546         public string SelectWeekText {
547             get {
548                 object s = ViewState["SelectWeekText"];
549                 return((s == null) ? "&gt;" : (String) s);
550             }
551             set {
552                 ViewState["SelectWeekText"] = value;
553             }
554         }
555
556
557         /// <devdoc>
558         ///    <para>Gets or sets
559         ///       a value indicating whether the days of the week are displayed.</para>
560         /// </devdoc>
561         [
562         WebCategory("Appearance"),
563         DefaultValue(true),
564         WebSysDescription(SR.Calendar_ShowDayHeader)
565         ]
566         public bool ShowDayHeader {
567             get {
568                 object b = ViewState["ShowDayHeader"];
569                 return((b == null) ? true : (bool)b);
570             }
571             set {
572                 ViewState["ShowDayHeader"] = value;
573             }
574         }
575
576
577         /// <devdoc>
578         ///    <para>Gets or set
579         ///       a value indicating whether days on the calendar are displayed with a border.</para>
580         /// </devdoc>
581         [
582         WebCategory("Appearance"),
583         DefaultValue(false),
584         WebSysDescription(SR.Calendar_ShowGridLines)
585         ]
586         public bool ShowGridLines {
587             get {
588                 object b= ViewState["ShowGridLines"];
589                 return((b == null) ? false : (bool)b);
590             }
591             set {
592                 ViewState["ShowGridLines"] = value;
593             }
594         }
595
596
597         /// <devdoc>
598         /// <para>Gets or sets a value indicating whether the <see cref='System.Web.UI.WebControls.Calendar'/>
599         /// displays the next and pervious month
600         /// hyperlinks in the title.</para>
601         /// </devdoc>
602         [
603         WebCategory("Appearance"),
604         DefaultValue(true),
605         WebSysDescription(SR.Calendar_ShowNextPrevMonth)
606         ]
607         public bool ShowNextPrevMonth {
608             get {
609                 object b = ViewState["ShowNextPrevMonth"];
610                 return((b == null) ? true : (bool)b);
611             }
612             set {
613                 ViewState["ShowNextPrevMonth"] = value;
614             }
615         }
616
617
618         /// <devdoc>
619         ///    <para> Gets or
620         ///       sets a value indicating whether the title is displayed.</para>
621         /// </devdoc>
622         [
623         WebCategory("Appearance"),
624         DefaultValue(true),
625         WebSysDescription(SR.Calendar_ShowTitle)
626         ]
627         public bool ShowTitle {
628             get {
629                 object b = ViewState["ShowTitle"];
630                 return((b == null) ? true : (bool)b);
631             }
632             set {
633                 ViewState["ShowTitle"] = value;
634             }
635         }
636
637
638         /// <devdoc>
639         ///    <para>Gets or sets how the month name is formatted in the title
640         ///       bar.</para>
641         /// </devdoc>
642         [
643         WebCategory("Appearance"),
644         DefaultValue(TitleFormat.MonthYear),
645         WebSysDescription(SR.Calendar_TitleFormat)
646         ]
647         public TitleFormat TitleFormat {
648             get {
649                 object tf = ViewState["TitleFormat"];
650                 return((tf == null) ? TitleFormat.MonthYear : (TitleFormat)tf);
651             }
652             set {
653                 if (value < TitleFormat.Month || value > TitleFormat.MonthYear) {
654                     throw new ArgumentOutOfRangeException("value");
655                 }
656                 ViewState["TitleFormat"] = value;
657             }
658         }
659
660
661         /// <devdoc>
662         /// <para>Gets the style properties of the <see cref='System.Web.UI.WebControls.Calendar'/> title. This property is
663         ///    read-only.</para>
664         /// </devdoc>
665         [
666         WebCategory("Styles"),
667         WebSysDescription(SR.Calendar_TitleStyle),
668         DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
669         NotifyParentProperty(true),
670         PersistenceMode(PersistenceMode.InnerProperty),
671         ]
672         public TableItemStyle TitleStyle {
673             get {
674                 if (titleStyle == null) {
675                     titleStyle = new TableItemStyle();
676                     if (IsTrackingViewState)
677                         ((IStateManager)titleStyle).TrackViewState();
678                 }
679                 return titleStyle;
680             }
681         }
682
683
684         /// <devdoc>
685         ///    <para>Gets the style properties for today's date on the
686         ///    <see cref='System.Web.UI.WebControls.Calendar'/>. This
687         ///       property is read-only.</para>
688         /// </devdoc>
689         [
690         WebCategory("Styles"),
691         DefaultValue(null),
692         WebSysDescription(SR.Calendar_TodayDayStyle),
693         DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
694         NotifyParentProperty(true),
695         PersistenceMode(PersistenceMode.InnerProperty)
696         ]
697         public TableItemStyle TodayDayStyle {
698             get {
699                 if (todayDayStyle == null) {
700                     todayDayStyle = new TableItemStyle();
701                     if (IsTrackingViewState)
702                         ((IStateManager)todayDayStyle).TrackViewState();
703                 }
704                 return todayDayStyle;
705             }
706         }
707
708
709         /// <devdoc>
710         ///    <para>Gets or sets the value to use as today's date.</para>
711         /// </devdoc>
712         [
713         Browsable(false),
714         WebSysDescription(SR.Calendar_TodaysDate),
715         DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
716         ]
717         public DateTime TodaysDate {
718             get {
719                 object o = ViewState["TodaysDate"];
720                 return((o == null) ? DateTime.Today : (DateTime)o);
721             }
722             set {
723                 ViewState["TodaysDate"] = value.Date;
724             }
725         }
726
727
728         [
729         DefaultValue(true),
730         WebCategory("Accessibility"),
731         WebSysDescription(SR.Table_UseAccessibleHeader)
732         ]
733         public virtual bool UseAccessibleHeader {
734             get {
735                 object o = ViewState["UseAccessibleHeader"];
736                 return (o != null) ? (bool)o : true;
737             }
738             set {
739                 ViewState["UseAccessibleHeader"] = value;
740             }
741         }
742
743
744         /// <devdoc>
745         ///    <para>Gets or sets the date that specifies what month to display. The date can be
746         ///       be any date within the month.</para>
747         /// </devdoc>
748         [
749         Bindable(true),
750         DefaultValue(typeof(DateTime), "1/1/0001"),
751         WebSysDescription(SR.Calendar_VisibleDate)
752         ]
753         public DateTime VisibleDate {
754             get {
755                 object o = ViewState["VisibleDate"];
756                 return((o == null) ? DateTime.MinValue : (DateTime)o);
757             }
758             set {
759                 ViewState["VisibleDate"] = value.Date;
760             }
761         }
762
763
764         /// <devdoc>
765         ///    <para>Gets the style properties for the displaying weekend dates. This property is
766         ///       read-only.</para>
767         /// </devdoc>
768         [
769         WebCategory("Styles"),
770         WebSysDescription(SR.Calendar_WeekendDayStyle),
771         DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
772         NotifyParentProperty(true),
773         PersistenceMode(PersistenceMode.InnerProperty)
774         ]
775         public TableItemStyle WeekendDayStyle {
776             get {
777                 if (weekendDayStyle == null) {
778                     weekendDayStyle = new TableItemStyle();
779                     if (IsTrackingViewState)
780                         ((IStateManager)weekendDayStyle).TrackViewState();
781                 }
782                 return weekendDayStyle;
783             }
784         }
785
786
787
788         /// <devdoc>
789         /// <para>Occurs when each day is created in teh control hierarchy for the <see cref='System.Web.UI.WebControls.Calendar'/>.</para>
790         /// </devdoc>
791         [
792         WebCategory("Action"),
793         WebSysDescription(SR.Calendar_OnDayRender)
794         ]
795         public event DayRenderEventHandler DayRender {
796             add {
797                 Events.AddHandler(EventDayRender, value);
798             }
799             remove {
800                 Events.RemoveHandler(EventDayRender, value);
801             }
802         }
803
804
805
806
807         /// <devdoc>
808         ///    <para>Occurs when the user clicks on a day, week, or month
809         ///       selector and changes the <see cref='System.Web.UI.WebControls.Calendar.SelectedDate'/>.</para>
810         /// </devdoc>
811         [
812         WebCategory("Action"),
813         WebSysDescription(SR.Calendar_OnSelectionChanged)
814         ]
815         public event EventHandler SelectionChanged {
816             add {
817                 Events.AddHandler(EventSelectionChanged, value);
818             }
819             remove {
820                 Events.RemoveHandler(EventSelectionChanged, value);
821             }
822         }
823
824
825
826         /// <devdoc>
827         ///    <para>Occurs when the
828         ///       user clicks on the next or previous month <see cref='System.Web.UI.WebControls.Button'/> controls on the title.</para>
829         /// </devdoc>
830         [
831         WebCategory("Action"),
832         WebSysDescription(SR.Calendar_OnVisibleMonthChanged)
833         ]
834         public event MonthChangedEventHandler VisibleMonthChanged {
835             add {
836                 Events.AddHandler(EventVisibleMonthChanged, value);
837             }
838             remove {
839                 Events.RemoveHandler(EventVisibleMonthChanged, value);
840             }
841         }
842
843         // Methods
844
845
846         /// <devdoc>
847         /// </devdoc>
848         private void ApplyTitleStyle(TableCell titleCell, Table titleTable, TableItemStyle titleStyle) {
849             // apply affects that affect the whole background to the cell
850             if (titleStyle.BackColor != Color.Empty) {
851                 titleCell.BackColor = titleStyle.BackColor;
852             }
853             if (titleStyle.BorderColor != Color.Empty) {
854                 titleCell.BorderColor = titleStyle.BorderColor;
855             }
856             if (titleStyle.BorderWidth != Unit.Empty) {
857                 titleCell.BorderWidth= titleStyle.BorderWidth;
858             }
859             if (titleStyle.BorderStyle != BorderStyle.NotSet) {
860                 titleCell.BorderStyle = titleStyle.BorderStyle;
861             }
862             if (titleStyle.Height != Unit.Empty) {
863                 titleCell.Height = titleStyle.Height;
864             }
865             if (titleStyle.VerticalAlign != VerticalAlign.NotSet) {
866                 titleCell.VerticalAlign = titleStyle.VerticalAlign;
867             }
868
869             // apply affects that affect everything else to the table
870             if (titleStyle.CssClass.Length > 0) {
871                 titleTable.CssClass = titleStyle.CssClass;
872             }
873             else if (CssClass.Length > 0) {
874                 titleTable.CssClass = CssClass;
875             }
876
877             if (titleStyle.ForeColor != Color.Empty) {
878                 titleTable.ForeColor = titleStyle.ForeColor;
879             }
880             else if (ForeColor != Color.Empty) {
881                 titleTable.ForeColor = ForeColor;
882             }
883             titleTable.Font.CopyFrom(titleStyle.Font);
884             titleTable.Font.MergeWith(this.Font);
885
886         }
887
888
889         /// <internalonly/>
890         /// <devdoc>
891         /// </devdoc>
892         protected override ControlCollection CreateControlCollection() {
893             return new InternalControlCollection(this);
894         }
895
896
897
898         /// <devdoc>
899         /// </devdoc>
900         private DateTime EffectiveVisibleDate() {
901             DateTime visDate = VisibleDate;
902             if (visDate.Equals(DateTime.MinValue)) {
903                 visDate = TodaysDate;
904             }
905
906             // VSWhidbey 366243
907             if (IsMinSupportedYearMonth(visDate)) {
908                 return minSupportedDate;
909             }
910             else {
911                 return threadCalendar.AddDays(visDate, -(threadCalendar.GetDayOfMonth(visDate) - 1));
912             }
913         }
914
915
916         /// <devdoc>
917         /// </devdoc>
918         private DateTime FirstCalendarDay(DateTime visibleDate) {
919             DateTime firstDayOfMonth = visibleDate;
920
921             // VSWhidbey 366243
922             if (IsMinSupportedYearMonth(firstDayOfMonth)) {
923                 return firstDayOfMonth;
924             }
925
926             int daysFromLastMonth = ((int)threadCalendar.GetDayOfWeek(firstDayOfMonth)) - NumericFirstDayOfWeek();
927             // Always display at least one day from the previous month
928             if (daysFromLastMonth <= 0) {
929                 daysFromLastMonth += 7;
930             }
931             return threadCalendar.AddDays(firstDayOfMonth, -daysFromLastMonth);
932         }
933
934
935         /// <devdoc>
936         /// </devdoc>
937         private string GetCalendarButtonText(string eventArgument, string buttonText, string title, bool showLink, Color foreColor) {
938             if (showLink) {
939                 StringBuilder sb = new StringBuilder();
940                 sb.Append("<a href=\"");
941                 sb.Append(Page.ClientScript.GetPostBackClientHyperlink(this, eventArgument, true));
942
943                 // ForeColor needs to go on the actual link. This breaks the uplevel/downlevel rules a little bit,
944                 // but it is worth doing so the day links do not change color when they go in the history on
945                 // downlevel browsers. Otherwise, people get it confused with the selection mechanism.
946                 sb.Append("\" style=\"color:");
947                 sb.Append(foreColor.IsEmpty ? defaultButtonColorText : ColorTranslator.ToHtml(foreColor));
948
949                 if (!String.IsNullOrEmpty(title)) {
950                     sb.Append("\" title=\"");
951                     sb.Append(title);
952                 }
953
954                 sb.Append("\">");
955                 sb.Append(buttonText);
956                 sb.Append("</a>");
957                 return sb.ToString();
958             }
959             else {
960                 return buttonText;
961             }
962         }
963
964
965         /// <devdoc>
966         /// </devdoc>
967         private int GetDefinedStyleMask() {
968
969             // Selected is always defined because it has default effects
970             int styleMask = STYLEMASK_SELECTED;
971
972             if (dayStyle != null && !dayStyle.IsEmpty)
973                 styleMask |= STYLEMASK_DAY;
974             if (todayDayStyle != null && !todayDayStyle.IsEmpty)
975                 styleMask |= STYLEMASK_TODAY;
976             if (otherMonthDayStyle != null && !otherMonthDayStyle.IsEmpty)
977                 styleMask |= STYLEMASK_OTHERMONTH;
978             if (weekendDayStyle != null && !weekendDayStyle.IsEmpty)
979                 styleMask |= STYLEMASK_WEEKEND;
980             return styleMask;
981         }
982
983
984         /// <devdoc>
985         /// </devdoc>
986         private string GetMonthName(int m, bool bFull) {
987             if (bFull) {
988                 return DateTimeFormatInfo.CurrentInfo.GetMonthName(m);
989             }
990             else {
991                 return DateTimeFormatInfo.CurrentInfo.GetAbbreviatedMonthName(m);
992             }
993         }
994
995
996         /// <devdoc>
997         /// <para>Determines if a <see cref='System.Web.UI.WebControls.CalendarSelectionMode'/>
998         /// contains week selectors.</para>
999         /// </devdoc>
1000         protected bool HasWeekSelectors(CalendarSelectionMode selectionMode) {
1001             return(selectionMode == CalendarSelectionMode.DayWeek
1002                    || selectionMode == CalendarSelectionMode.DayWeekMonth);
1003         }
1004
1005         private bool IsTheSameYearMonth(DateTime date1, DateTime date2) {
1006 #if DEBUG
1007             Debug.Assert(threadCalendarInitialized);
1008 #endif
1009             return (threadCalendar.GetEra(date1) == threadCalendar.GetEra(date2) &&
1010                     threadCalendar.GetYear(date1) == threadCalendar.GetYear(date2) &&
1011                     threadCalendar.GetMonth(date1) == threadCalendar.GetMonth(date2));
1012         }
1013
1014         private bool IsMinSupportedYearMonth(DateTime date) {
1015 #if DEBUG
1016             Debug.Assert(threadCalendarInitialized);
1017 #endif
1018             return IsTheSameYearMonth(minSupportedDate, date);
1019         }
1020
1021         private bool IsMaxSupportedYearMonth(DateTime date) {
1022 #if DEBUG
1023             Debug.Assert(threadCalendarInitialized);
1024 #endif
1025             return IsTheSameYearMonth(maxSupportedDate, date);
1026         }
1027
1028         /// <internalonly/>
1029         /// <devdoc>
1030         /// <para>Loads a saved state of the <see cref='System.Web.UI.WebControls.Calendar'/>. </para>
1031         /// </devdoc>
1032         protected override void LoadViewState(object savedState) {
1033             if (savedState != null) {
1034                 object[] myState = (object[])savedState;
1035
1036                 if (myState[0] != null)
1037                     base.LoadViewState(myState[0]);
1038                 if (myState[1] != null)
1039                     ((IStateManager)TitleStyle).LoadViewState(myState[1]);
1040                 if (myState[2] != null)
1041                     ((IStateManager)NextPrevStyle).LoadViewState(myState[2]);
1042                 if (myState[3] != null)
1043                     ((IStateManager)DayStyle).LoadViewState(myState[3]);
1044                 if (myState[4] != null)
1045                     ((IStateManager)DayHeaderStyle).LoadViewState(myState[4]);
1046                 if (myState[5] != null)
1047                     ((IStateManager)TodayDayStyle).LoadViewState(myState[5]);
1048                 if (myState[6] != null)
1049                     ((IStateManager)WeekendDayStyle).LoadViewState(myState[6]);
1050                 if (myState[7] != null)
1051                     ((IStateManager)OtherMonthDayStyle).LoadViewState(myState[7]);
1052                 if (myState[8] != null)
1053                     ((IStateManager)SelectedDayStyle).LoadViewState(myState[8]);
1054                 if (myState[9] != null)
1055                     ((IStateManager)SelectorStyle).LoadViewState(myState[9]);
1056
1057                 ArrayList selDates = (ArrayList)ViewState["SD"];
1058                 if (selDates != null) {
1059                     dateList = selDates;
1060                     selectedDates = null;   // reset wrapper collection
1061                 }
1062
1063             }
1064         }
1065
1066
1067         /// <internalonly/>
1068         /// <devdoc>
1069         ///    <para>Marks the starting point to begin tracking and saving changes to the
1070         ///       control as part of the control viewstate.</para>
1071         /// </devdoc>
1072         protected override void TrackViewState() {
1073             base.TrackViewState();
1074
1075             if (titleStyle != null)
1076                 ((IStateManager)titleStyle).TrackViewState();
1077             if (nextPrevStyle != null)
1078                 ((IStateManager)nextPrevStyle).TrackViewState();
1079             if (dayStyle != null)
1080                 ((IStateManager)dayStyle).TrackViewState();
1081             if (dayHeaderStyle != null)
1082                 ((IStateManager)dayHeaderStyle).TrackViewState();
1083             if (todayDayStyle != null)
1084                 ((IStateManager)todayDayStyle).TrackViewState();
1085             if (weekendDayStyle != null)
1086                 ((IStateManager)weekendDayStyle).TrackViewState();
1087             if (otherMonthDayStyle != null)
1088                 ((IStateManager)otherMonthDayStyle).TrackViewState();
1089             if (selectedDayStyle != null)
1090                 ((IStateManager)selectedDayStyle).TrackViewState();
1091             if (selectorStyle != null)
1092                 ((IStateManager)selectorStyle).TrackViewState();
1093         }
1094
1095
1096         /// <devdoc>
1097         /// </devdoc>
1098         private int NumericFirstDayOfWeek() {
1099             // Used globalized value by default
1100             return(FirstDayOfWeek == FirstDayOfWeek.Default)
1101             ? (int) DateTimeFormatInfo.CurrentInfo.FirstDayOfWeek
1102             : (int) FirstDayOfWeek;
1103         }
1104
1105
1106         /// <devdoc>
1107         /// <para>Raises the <see langword='DayRender '/>event for a <see cref='System.Web.UI.WebControls.Calendar'/>.</para>
1108         /// </devdoc>
1109         protected virtual void OnDayRender(TableCell cell, CalendarDay day) {
1110             DayRenderEventHandler handler = (DayRenderEventHandler)Events[EventDayRender];
1111             if (handler != null) {
1112                 int absoluteDay = day.Date.Subtract(baseDate).Days;
1113
1114                 // VSWhidbey 215383: We return null for selectUrl if a control is not in
1115                 // the page control tree.
1116                 string selectUrl = null;
1117                 Page page = Page;
1118                 if (page != null) {
1119                     string eventArgument = absoluteDay.ToString(CultureInfo.InvariantCulture);
1120                     selectUrl = Page.ClientScript.GetPostBackClientHyperlink(this, eventArgument, true);
1121                 }
1122                 handler(this, new DayRenderEventArgs(cell, day, selectUrl));
1123             }
1124         }
1125
1126         /// <devdoc>
1127         /// <para>Raises the <see langword='SelectionChanged '/>event for a <see cref='System.Web.UI.WebControls.Calendar'/>.</para>
1128         /// </devdoc>
1129         protected virtual void OnSelectionChanged() {
1130             EventHandler handler = (EventHandler)Events[EventSelectionChanged];
1131             if (handler != null) {
1132                 handler(this, EventArgs.Empty);
1133             }
1134         }
1135
1136
1137         /// <devdoc>
1138         /// <para>Raises the <see langword='VisibleMonthChanged '/>event for a <see cref='System.Web.UI.WebControls.Calendar'/>.</para>
1139         /// </devdoc>
1140         protected virtual void OnVisibleMonthChanged(DateTime newDate, DateTime previousDate) {
1141             MonthChangedEventHandler handler = (MonthChangedEventHandler)Events[EventVisibleMonthChanged];
1142             if (handler != null) {
1143                 handler(this, new MonthChangedEventArgs(newDate, previousDate));
1144             }
1145         }
1146
1147
1148         /// <internalonly/>
1149         /// <devdoc>
1150         /// <para>Raises events on post back for the <see cref='System.Web.UI.WebControls.Calendar'/> control.</para>
1151         /// </devdoc>
1152         protected virtual void RaisePostBackEvent(string eventArgument) {
1153
1154             ValidateEvent(UniqueID, eventArgument);
1155
1156             if (AdapterInternal != null) {
1157                 IPostBackEventHandler pbeh = AdapterInternal as IPostBackEventHandler;
1158                 if (pbeh != null) {
1159                     pbeh.RaisePostBackEvent(eventArgument);
1160                 }
1161             } else {
1162
1163                 if (String.Compare(eventArgument, 0, NAVIGATE_MONTH_COMMAND, 0, NAVIGATE_MONTH_COMMAND.Length, StringComparison.Ordinal) == 0) {
1164                     // Month navigation. The command starts with a "V" and the remainder is day difference from the
1165                     // base date.
1166                     DateTime oldDate = VisibleDate;
1167                     if (oldDate.Equals(DateTime.MinValue)) {
1168                         oldDate = TodaysDate;
1169                     }
1170                     int newDateDiff = Int32.Parse(eventArgument.Substring(NAVIGATE_MONTH_COMMAND.Length), CultureInfo.InvariantCulture);
1171                     VisibleDate = baseDate.AddDays(newDateDiff);
1172                     if (VisibleDate == DateTime.MinValue) {
1173                         // MinValue would make the calendar shows today's month instead because it
1174                         // is the default value of VisibleDate property, so we add a day to keep
1175                         // showing the first supported month.
1176                         // We assume the first supported month has more than one day.
1177                         VisibleDate = DateTimeFormatInfo.CurrentInfo.Calendar.AddDays(VisibleDate, 1);
1178                     }
1179                     OnVisibleMonthChanged(VisibleDate, oldDate);
1180                 }
1181                 else if (String.Compare(eventArgument, 0, SELECT_RANGE_COMMAND, 0, SELECT_RANGE_COMMAND.Length, StringComparison.Ordinal) == 0) {
1182                     // Range selection. The command starts with an "R". The remainder is an integer. When divided by 100
1183                     // the result is the day difference from the base date of the first day, and the remainder is the
1184                     // number of days to select.
1185                     int rangeValue = Int32.Parse(eventArgument.Substring(SELECT_RANGE_COMMAND.Length), CultureInfo.InvariantCulture);
1186                     int dayDiff = rangeValue / 100;
1187                     int dayRange = rangeValue % 100;
1188                     if (dayRange < 1) {
1189                         dayRange = 100 + dayRange;
1190                         dayDiff -= 1;
1191                     }
1192                     DateTime dt = baseDate.AddDays(dayDiff);
1193                     SelectRange(dt, dt.AddDays(dayRange - 1));
1194                 }
1195                 else {
1196                     // Single day selection. This is just a number which is the day difference from the base date.
1197                     int dayDiff = Int32.Parse(eventArgument, CultureInfo.InvariantCulture);
1198                     DateTime dt = baseDate.AddDays(dayDiff);
1199                     SelectRange(dt, dt);
1200                 }
1201             }
1202         }
1203
1204
1205         void IPostBackEventHandler.RaisePostBackEvent(string eventArgument) {
1206             RaisePostBackEvent(eventArgument);
1207         }
1208
1209
1210         /// <internalonly/>
1211         protected internal override void OnPreRender(EventArgs e) {
1212             base.OnPreRender(e);
1213             if (Page != null) {
1214                 Page.RegisterPostBackScript();
1215             }
1216         }
1217
1218
1219         /// <internalonly/>
1220         /// <devdoc>
1221         /// <para>Displays the <see cref='System.Web.UI.WebControls.Calendar'/> control on the client.</para>
1222         /// </devdoc>
1223         protected internal override void Render(HtmlTextWriter writer) {
1224             threadCalendar = DateTimeFormatInfo.CurrentInfo.Calendar;
1225             minSupportedDate = threadCalendar.MinSupportedDateTime;
1226             maxSupportedDate = threadCalendar.MaxSupportedDateTime;
1227 #if DEBUG
1228             threadCalendarInitialized = true;
1229 #endif
1230             DateTime visibleDate = EffectiveVisibleDate();
1231             DateTime firstDay = FirstCalendarDay(visibleDate);
1232             CalendarSelectionMode selectionMode = SelectionMode;
1233
1234             // Make sure we are in a form tag with runat=server.
1235             if (Page != null) {
1236                 Page.VerifyRenderingInServerForm(this);
1237             }
1238
1239             // We only want to display the link if we have a page, or if we are on the design surface
1240             // If we can stops links being active on the Autoformat dialog, then we can remove this these checks.
1241             Page page = Page;
1242             bool buttonsActive;
1243             if (page == null || DesignMode) {
1244                 buttonsActive = false;
1245             }
1246             else {
1247                 buttonsActive = IsEnabled;
1248             }
1249
1250             defaultForeColor = ForeColor;
1251             if (defaultForeColor == Color.Empty) {
1252                 defaultForeColor = DefaultForeColor;
1253             }
1254             defaultButtonColorText = ColorTranslator.ToHtml(defaultForeColor);
1255
1256             Table table = new Table();
1257
1258             if (ID != null) {
1259                 table.ID = ClientID;
1260             }
1261             table.CopyBaseAttributes(this);
1262             if (ControlStyleCreated) {
1263                 table.ApplyStyle(ControlStyle);
1264             }
1265             table.Width = Width;
1266             table.Height = Height;
1267             table.CellPadding = CellPadding;
1268             table.CellSpacing = CellSpacing;
1269
1270             // default look
1271             if ((ControlStyleCreated == false) ||
1272                 (ControlStyle.IsSet(System.Web.UI.WebControls.Style.PROP_BORDERWIDTH) == false) ||
1273                 BorderWidth.Equals(Unit.Empty)) {
1274                 table.BorderWidth = Unit.Pixel(1);
1275             }
1276
1277             if (ShowGridLines) {
1278                 table.GridLines = GridLines.Both;
1279             }
1280             else {
1281                 table.GridLines = GridLines.None;
1282             }
1283
1284             bool useAccessibleHeader = UseAccessibleHeader;
1285             if (useAccessibleHeader) {
1286                 if (table.Attributes["title"] == null) {
1287                     table.Attributes["title"] = SR.GetString(SR.Calendar_TitleText);
1288                 }
1289             }
1290
1291             string caption = Caption;
1292             if (caption.Length > 0) {
1293                 table.Caption = caption;
1294                 table.CaptionAlign = CaptionAlign;
1295             }
1296
1297             table.RenderBeginTag(writer);
1298
1299             if (ShowTitle) {
1300                 RenderTitle(writer, visibleDate, selectionMode, buttonsActive, useAccessibleHeader);
1301             }
1302
1303             if (ShowDayHeader) {
1304                 RenderDayHeader(writer, visibleDate, selectionMode, buttonsActive, useAccessibleHeader);
1305             }
1306
1307             RenderDays(writer, firstDay, visibleDate, selectionMode, buttonsActive, useAccessibleHeader);
1308
1309             table.RenderEndTag(writer);
1310         }
1311
1312         private void RenderCalendarCell(HtmlTextWriter writer, TableItemStyle style, string text, string title, bool hasButton, string eventArgument) {
1313             style.AddAttributesToRender(writer, this);
1314             writer.RenderBeginTag(HtmlTextWriterTag.Td);
1315
1316             if (hasButton) {
1317
1318                 // render the button
1319                 Color foreColor = style.ForeColor;
1320                 writer.Write("<a href=\"");
1321                 writer.Write(Page.ClientScript.GetPostBackClientHyperlink(this, eventArgument, true));
1322
1323                 // ForeColor needs to go on the actual link. This breaks the uplevel/downlevel rules a little bit,
1324                 // but it is worth doing so the day links do not change color when they go in the history on
1325                 // downlevel browsers. Otherwise, people get it confused with the selection mechanism.
1326                 writer.Write("\" style=\"color:");
1327                 writer.Write(foreColor.IsEmpty ? defaultButtonColorText : ColorTranslator.ToHtml(foreColor));
1328
1329                 if (!String.IsNullOrEmpty(title)) {
1330                     writer.Write("\" title=\"");
1331                     writer.Write(title);
1332                 }
1333
1334                 writer.Write("\">");
1335                 writer.Write(text);
1336                 writer.Write("</a>");
1337             }
1338             else {
1339                 writer.Write(text);
1340             }
1341
1342             writer.RenderEndTag();
1343         }
1344
1345         private void RenderCalendarHeaderCell(HtmlTextWriter writer, TableItemStyle style, string text, string abbrText) {
1346             style.AddAttributesToRender(writer, this);
1347             writer.AddAttribute("abbr", abbrText);
1348             writer.AddAttribute("scope", "col");
1349             writer.RenderBeginTag(HtmlTextWriterTag.Th);
1350             writer.Write(text);
1351             writer.RenderEndTag();
1352         }
1353
1354
1355         /// <devdoc>
1356         /// </devdoc>
1357         private void RenderDayHeader(HtmlTextWriter writer, DateTime visibleDate, CalendarSelectionMode selectionMode, bool buttonsActive, bool useAccessibleHeader) {
1358
1359             writer.Write(ROWBEGINTAG);
1360
1361             DateTimeFormatInfo dtf = DateTimeFormatInfo.CurrentInfo;
1362
1363             if (HasWeekSelectors(selectionMode)) {
1364                 TableItemStyle monthSelectorStyle = new TableItemStyle();
1365                 monthSelectorStyle.HorizontalAlign = HorizontalAlign.Center;
1366                 // add the month selector button if required;
1367                 if (selectionMode == CalendarSelectionMode.DayWeekMonth) {
1368
1369                     // Range selection. The command starts with an "R". The remainder is an integer. When divided by 100
1370                     // the result is the day difference from the base date of the first day, and the remainder is the
1371                     // number of days to select.
1372                     int startOffset = visibleDate.Subtract(baseDate).Days;
1373                     int monthLength = threadCalendar.GetDaysInMonth(threadCalendar.GetYear(visibleDate), threadCalendar.GetMonth(visibleDate), threadCalendar.GetEra(visibleDate));
1374                     if (IsMinSupportedYearMonth(visibleDate)) {
1375                         // The first supported month might not start with day 1
1376                         // (e.g. Sept 8 is the first supported date of JapaneseCalendar)
1377                         monthLength = monthLength - threadCalendar.GetDayOfMonth(visibleDate) + 1;
1378                     }
1379                     else if (IsMaxSupportedYearMonth(visibleDate)) {
1380                         // The last supported month might not have all days supported in that calendar month
1381                         // (e.g. April 3 is the last supported date of HijriCalendar)
1382                         monthLength = threadCalendar.GetDayOfMonth(maxSupportedDate);
1383                     }
1384
1385                     string monthSelectKey = SELECT_RANGE_COMMAND + ((startOffset * 100) + monthLength).ToString(CultureInfo.InvariantCulture);
1386                     monthSelectorStyle.CopyFrom(SelectorStyle);
1387
1388                     string selectMonthTitle = null;
1389                     if (useAccessibleHeader) {
1390                         selectMonthTitle = SR.GetString(SR.Calendar_SelectMonthTitle);
1391                     }
1392                     RenderCalendarCell(writer, monthSelectorStyle, SelectMonthText, selectMonthTitle, buttonsActive, monthSelectKey);
1393                 }
1394                 else {
1395                     // otherwise make it look like the header row
1396                     monthSelectorStyle.CopyFrom(DayHeaderStyle);
1397                     RenderCalendarCell(writer, monthSelectorStyle, string.Empty, null, false, null);
1398                 }
1399             }
1400
1401             TableItemStyle dayNameStyle = new TableItemStyle();
1402             dayNameStyle.HorizontalAlign = HorizontalAlign.Center;
1403             dayNameStyle.CopyFrom(DayHeaderStyle);
1404             DayNameFormat dayNameFormat = DayNameFormat;
1405
1406             int numericFirstDay = NumericFirstDayOfWeek();
1407             for (int i = numericFirstDay; i < numericFirstDay + 7; i++) {
1408                 string dayName;
1409                 int dayOfWeek = i % 7;
1410                 switch (dayNameFormat) {
1411                     case DayNameFormat.FirstLetter:
1412                         dayName = dtf.GetDayName((DayOfWeek)dayOfWeek).Substring(0, 1);
1413                         break;
1414                     case DayNameFormat.FirstTwoLetters:
1415                         dayName = dtf.GetDayName((DayOfWeek)dayOfWeek).Substring(0, 2);
1416                         break;
1417                     case DayNameFormat.Full:
1418                         dayName = dtf.GetDayName((DayOfWeek)dayOfWeek);
1419                         break;
1420                     case DayNameFormat.Short:
1421                         dayName = dtf.GetAbbreviatedDayName((DayOfWeek)dayOfWeek);
1422                         break;
1423                     case DayNameFormat.Shortest:
1424                         dayName = dtf.GetShortestDayName((DayOfWeek)dayOfWeek);
1425                         break;
1426                     default:
1427                         Debug.Assert(false, "Unknown DayNameFormat value!");
1428                         goto case DayNameFormat.Short;
1429                 }
1430
1431                 if (useAccessibleHeader) {
1432                     string fullDayName = dtf.GetDayName((DayOfWeek)dayOfWeek);
1433                     RenderCalendarHeaderCell(writer, dayNameStyle, dayName, fullDayName);
1434                 }
1435                 else {
1436                     RenderCalendarCell(writer, dayNameStyle, dayName, null, false, null);
1437                 }
1438             }
1439             writer.Write(ROWENDTAG);
1440         }
1441
1442
1443         /// <devdoc>
1444         /// </devdoc>
1445         private void RenderDays(HtmlTextWriter writer, DateTime firstDay, DateTime visibleDate, CalendarSelectionMode selectionMode, bool buttonsActive, bool useAccessibleHeader) {
1446             // Now add the rows for the actual days
1447
1448             DateTime d = firstDay;
1449             TableItemStyle weekSelectorStyle = null;
1450             Unit defaultWidth;
1451             bool hasWeekSelectors = HasWeekSelectors(selectionMode);
1452             if (hasWeekSelectors) {
1453                 weekSelectorStyle = new TableItemStyle();
1454                 weekSelectorStyle.Width = Unit.Percentage(12);
1455                 weekSelectorStyle.HorizontalAlign = HorizontalAlign.Center;
1456                 weekSelectorStyle.CopyFrom(SelectorStyle);
1457                 defaultWidth = Unit.Percentage(12);
1458             }
1459             else {
1460                 defaultWidth = Unit.Percentage(14);
1461             }
1462
1463             // This determines whether we need to call DateTime.ToString for each day. The only culture/calendar
1464             // that requires this for now is the HebrewCalendar.
1465             bool usesStandardDayDigits = !(threadCalendar is HebrewCalendar);
1466
1467             // This determines whether we can write out cells directly, or whether we have to create whole
1468             // TableCell objects for each day.
1469             bool hasRenderEvent = (this.GetType() != typeof(Calendar)
1470                                    || Events[EventDayRender] != null);
1471
1472             TableItemStyle [] cellStyles = new TableItemStyle[16];
1473             int definedStyleMask = GetDefinedStyleMask();
1474             DateTime todaysDate = TodaysDate;
1475             string selectWeekText = SelectWeekText;
1476             bool daysSelectable = buttonsActive && (selectionMode != CalendarSelectionMode.None);
1477             int visibleDateMonth = threadCalendar.GetMonth(visibleDate);
1478             int absoluteDay = firstDay.Subtract(baseDate).Days;
1479
1480             // VSWhidbey 480155: flag to indicate if forecolor needs to be set
1481             // explicitly in design mode to mimic runtime rendering with the
1482             // limitation of not supporting CSS class color setting.
1483             bool inDesignSelectionMode = (DesignMode && SelectionMode != CalendarSelectionMode.None);
1484
1485             //------------------------------------------------------------------
1486             // VSWhidbey 366243: The following variables are for boundary cases
1487             // such as the current visible month is the first or the last
1488             // supported month.  They are used in the 'for' loops below.
1489
1490             // For the first supported month, calculate how many days to
1491             // skip at the beginning of the first month.  E.g. JapaneseCalendar
1492             // starts at Sept 8.
1493             int numOfFirstDaysToSkip = 0;
1494             if (IsMinSupportedYearMonth(visibleDate)) {
1495                 numOfFirstDaysToSkip = (int)threadCalendar.GetDayOfWeek(firstDay) - NumericFirstDayOfWeek();
1496                 // If negative, it simply means the the index of the starting
1497                 // day name is greater than the day name of the first supported
1498                 // date.  We add back 7 to get the number of days to skip.
1499                 if (numOfFirstDaysToSkip < 0) {
1500                     numOfFirstDaysToSkip += 7;
1501                 }
1502             }
1503             Debug.Assert(numOfFirstDaysToSkip < 7);
1504
1505             // For the last or second last supported month, initialize variables
1506             // to identify the last supported date of the current calendar.
1507             // e.g. The last supported date of HijriCalendar is April 3.  When
1508             // the second last monthh is shown, it can be the case that not all
1509             // cells will be filled up.
1510             bool passedLastSupportedDate = false;
1511             DateTime secondLastMonth = threadCalendar.AddMonths(maxSupportedDate, -1);
1512             bool lastOrSecondLastMonth = (IsMaxSupportedYearMonth(visibleDate) ||
1513                                 IsTheSameYearMonth(secondLastMonth, visibleDate));
1514             //------------------------------------------------------------------
1515
1516             for (int iRow = 0; iRow < 6; iRow++) {
1517                 if (passedLastSupportedDate) {
1518                     break;
1519                 }
1520
1521                 writer.Write(ROWBEGINTAG);
1522
1523                 // add week selector column and button if required
1524                 if (hasWeekSelectors) {
1525                     // Range selection. The command starts with an "R". The remainder is an integer. When divided by 100
1526                     // the result is the day difference from the base date of the first day, and the remainder is the
1527                     // number of days to select.
1528                     int dayDiffParameter = (absoluteDay * 100) + 7;
1529
1530                     // Adjust the dayDiff for the first or the last supported month
1531                     if (numOfFirstDaysToSkip > 0) {
1532                         dayDiffParameter -= numOfFirstDaysToSkip;
1533                     }
1534                     else if (lastOrSecondLastMonth) {
1535                         int daysFromLastDate = maxSupportedDate.Subtract(d).Days;
1536                         if (daysFromLastDate < 6) {
1537                             dayDiffParameter -= (6 - daysFromLastDate);
1538                         }
1539                     }
1540                     string weekSelectKey = SELECT_RANGE_COMMAND + dayDiffParameter.ToString(CultureInfo.InvariantCulture);
1541
1542                     string selectWeekTitle = null;
1543                     if (useAccessibleHeader) {
1544                         int weekOfMonth = iRow + 1;
1545                         selectWeekTitle = SR.GetString(SR.Calendar_SelectWeekTitle, weekOfMonth.ToString(CultureInfo.InvariantCulture));
1546                     }
1547                     RenderCalendarCell(writer, weekSelectorStyle, selectWeekText, selectWeekTitle, buttonsActive, weekSelectKey);
1548                 }
1549
1550                 for (int iDay = 0; iDay < 7; iDay++) {
1551
1552                     // Render empty cells for special cases to handle the first
1553                     // or last supported month.
1554                     if (numOfFirstDaysToSkip > 0) {
1555                         iDay += numOfFirstDaysToSkip;
1556                         for ( ; numOfFirstDaysToSkip > 0; numOfFirstDaysToSkip--) {
1557                             writer.RenderBeginTag(HtmlTextWriterTag.Td);
1558                             writer.RenderEndTag();
1559                         }
1560                     }
1561                     else if (passedLastSupportedDate) {
1562                         for ( ; iDay < 7; iDay++) {
1563                             writer.RenderBeginTag(HtmlTextWriterTag.Td);
1564                             writer.RenderEndTag();
1565                         }
1566                         break;
1567                     }
1568
1569                     int dayOfWeek = (int)threadCalendar.GetDayOfWeek(d);
1570                     int dayOfMonth = threadCalendar.GetDayOfMonth(d);
1571                     string dayNumberText;
1572                     if ((dayOfMonth <= cachedNumberMax) && usesStandardDayDigits) {
1573                         dayNumberText = cachedNumbers[dayOfMonth];
1574                     }
1575                     else {
1576                         dayNumberText = d.ToString("dd", CultureInfo.CurrentCulture);
1577                     }
1578
1579                     CalendarDay day = new CalendarDay(d,
1580                                                       (dayOfWeek == 0 || dayOfWeek == 6), // IsWeekend
1581                                                       d.Equals(todaysDate), // IsToday
1582                                                       (selectedDates != null) && selectedDates.Contains(d), // IsSelected
1583                                                       threadCalendar.GetMonth(d) != visibleDateMonth, // IsOtherMonth
1584                                                       dayNumberText // Number Text
1585                                                       );
1586
1587                     int styleMask = STYLEMASK_DAY;
1588                     if (day.IsSelected)
1589                         styleMask |= STYLEMASK_SELECTED;
1590                     if (day.IsOtherMonth)
1591                         styleMask |= STYLEMASK_OTHERMONTH;
1592                     if (day.IsToday)
1593                         styleMask |= STYLEMASK_TODAY;
1594                     if (day.IsWeekend)
1595                         styleMask |= STYLEMASK_WEEKEND;
1596                     int dayStyleMask = definedStyleMask  & styleMask;
1597                     // determine the unique portion of the mask for the current calendar,
1598                     // which will strip out the day style bit
1599                     int dayStyleID = dayStyleMask & STYLEMASK_UNIQUE;
1600
1601                     TableItemStyle cellStyle = cellStyles[dayStyleID];
1602                     if (cellStyle == null) {
1603                         cellStyle = new TableItemStyle();
1604                         SetDayStyles(cellStyle, dayStyleMask, defaultWidth);
1605                         cellStyles[dayStyleID] = cellStyle;
1606                     }
1607
1608
1609                     string dayTitle = null;
1610                     if (useAccessibleHeader) {
1611                         dayTitle = d.ToString("m", CultureInfo.CurrentCulture);
1612                     }
1613
1614                     if (hasRenderEvent) {
1615
1616                         TableCell cdc = new TableCell();
1617                         cdc.ApplyStyle(cellStyle);
1618
1619                         LiteralControl dayContent = new LiteralControl(dayNumberText);
1620                         cdc.Controls.Add(dayContent);
1621
1622                         day.IsSelectable = daysSelectable;
1623
1624                         OnDayRender(cdc, day);
1625
1626                         // refresh the day content
1627                         dayContent.Text = GetCalendarButtonText(absoluteDay.ToString(CultureInfo.InvariantCulture),
1628                                                                 dayNumberText,
1629                                                                 dayTitle,
1630                                                                 buttonsActive && day.IsSelectable,
1631                                                                 cdc.ForeColor);
1632                         cdc.RenderControl(writer);
1633
1634                     }
1635                     else {
1636                         // VSWhidbey 480155: In design mode we render days as
1637                         // texts instead of links so CSS class color setting is
1638                         // supported.  But this differs in runtime rendering
1639                         // where CSS class color setting is not supported.  To
1640                         // correctly mimic the forecolor of runtime rendering in
1641                         // design time, the default color, which is used in
1642                         // runtime rendering, is explicitly set in this case.
1643                         if (inDesignSelectionMode && cellStyle.ForeColor.IsEmpty) {
1644                             cellStyle.ForeColor = defaultForeColor;
1645                         }
1646
1647                         RenderCalendarCell(writer, cellStyle, dayNumberText, dayTitle, daysSelectable, absoluteDay.ToString(CultureInfo.InvariantCulture));
1648                     }
1649
1650                     Debug.Assert(!passedLastSupportedDate);
1651                     if (lastOrSecondLastMonth && d.Month == maxSupportedDate.Month && d.Day == maxSupportedDate.Day) {
1652                         passedLastSupportedDate = true;
1653                     }
1654                     else {
1655                         d = threadCalendar.AddDays(d, 1);
1656                         absoluteDay++;
1657                     }
1658                 }
1659                 writer.Write(ROWENDTAG);
1660             }
1661         }
1662
1663
1664         /// <devdoc>
1665         /// </devdoc>
1666         private void RenderTitle(HtmlTextWriter writer, DateTime visibleDate, CalendarSelectionMode selectionMode, bool buttonsActive, bool useAccessibleHeader) {
1667             writer.Write(ROWBEGINTAG);
1668
1669             TableCell titleCell = new TableCell();
1670             Table titleTable = new Table();
1671
1672             // default title table/cell styles
1673             titleCell.ColumnSpan = HasWeekSelectors(selectionMode) ? 8 : 7;
1674             titleCell.BackColor = Color.Silver;
1675             titleTable.GridLines = GridLines.None;
1676             titleTable.Width = Unit.Percentage(100);
1677             titleTable.CellSpacing = 0;
1678
1679             TableItemStyle titleStyle = TitleStyle;
1680             ApplyTitleStyle(titleCell, titleTable, titleStyle);
1681
1682             titleCell.RenderBeginTag(writer);
1683             titleTable.RenderBeginTag(writer);
1684             writer.Write(ROWBEGINTAG);
1685
1686             NextPrevFormat nextPrevFormat = NextPrevFormat;
1687
1688             TableItemStyle nextPrevStyle = new TableItemStyle();
1689             nextPrevStyle.Width = Unit.Percentage(15);
1690             nextPrevStyle.CopyFrom(NextPrevStyle);
1691             if (ShowNextPrevMonth) {
1692                 if (IsMinSupportedYearMonth(visibleDate)) {
1693                     writer.RenderBeginTag(HtmlTextWriterTag.Td);
1694                     writer.RenderEndTag();
1695                 }
1696                 else {
1697                     string prevMonthText;
1698                     if (nextPrevFormat == NextPrevFormat.ShortMonth || nextPrevFormat == NextPrevFormat.FullMonth) {
1699                         int monthNo = threadCalendar.GetMonth(threadCalendar.AddMonths(visibleDate, - 1));
1700                         prevMonthText = GetMonthName(monthNo, (nextPrevFormat == NextPrevFormat.FullMonth));
1701                     }
1702                     else {
1703                         prevMonthText = PrevMonthText;
1704                     }
1705                     // Month navigation. The command starts with a "V" and the remainder is day difference from the
1706                     // base date.
1707                     DateTime prevMonthDate;
1708
1709                     // VSWhidbey 366243: Some calendar's min supported date is
1710                     // not the first day of the month (e.g. JapaneseCalendar.
1711                     // So if we are setting the second supported month, the prev
1712                     // month link should always point to the first supported
1713                     // date instead of the first day of the previous month.
1714                     DateTime secondSupportedMonth = threadCalendar.AddMonths(minSupportedDate, 1);
1715                     if (IsTheSameYearMonth(secondSupportedMonth, visibleDate)) {
1716                         prevMonthDate = minSupportedDate;
1717                     }
1718                     else {
1719                         prevMonthDate = threadCalendar.AddMonths(visibleDate, -1);
1720                     }
1721
1722                     string prevMonthKey = NAVIGATE_MONTH_COMMAND + (prevMonthDate.Subtract(baseDate)).Days.ToString(CultureInfo.InvariantCulture);
1723
1724                     string previousMonthTitle = null;
1725                     if (useAccessibleHeader) {
1726                         previousMonthTitle = SR.GetString(SR.Calendar_PreviousMonthTitle);
1727                     }
1728                     RenderCalendarCell(writer, nextPrevStyle, prevMonthText, previousMonthTitle, buttonsActive, prevMonthKey);
1729                 }
1730             }
1731
1732
1733             TableItemStyle cellMainStyle = new TableItemStyle();
1734
1735             if (titleStyle.HorizontalAlign != HorizontalAlign.NotSet) {
1736                 cellMainStyle.HorizontalAlign = titleStyle.HorizontalAlign;
1737             }
1738             else {
1739                 cellMainStyle.HorizontalAlign = HorizontalAlign.Center;
1740             }
1741             cellMainStyle.Wrap = titleStyle.Wrap;
1742             cellMainStyle.Width = Unit.Percentage(70);
1743
1744             string titleText;
1745
1746             switch (TitleFormat) {
1747                 case TitleFormat.Month:
1748                     titleText = visibleDate.ToString("MMMM", CultureInfo.CurrentCulture);
1749                     break;
1750                 case TitleFormat.MonthYear:
1751                     string titlePattern = DateTimeFormatInfo.CurrentInfo.YearMonthPattern;
1752                     // Some cultures have a comma in their YearMonthPattern, which does not look
1753                     // right in a calendar. Use a fixed pattern for those.
1754                     if (titlePattern.IndexOf(',') >= 0) {
1755                         titlePattern = "MMMM yyyy";
1756                     }
1757                     titleText = visibleDate.ToString(titlePattern, CultureInfo.CurrentCulture);
1758                     break;
1759                 default:
1760                     Debug.Assert(false, "Unknown TitleFormat value!");
1761                     goto case TitleFormat.MonthYear;
1762             }
1763             RenderCalendarCell(writer, cellMainStyle, titleText, null, false, null);
1764
1765             if (ShowNextPrevMonth) {
1766                 if (IsMaxSupportedYearMonth(visibleDate)) {
1767                     writer.RenderBeginTag(HtmlTextWriterTag.Td);
1768                     writer.RenderEndTag();
1769                 }
1770                 else {
1771                     // Style for this one is identical bar
1772                     nextPrevStyle.HorizontalAlign = HorizontalAlign.Right;
1773                     string nextMonthText;
1774                     if (nextPrevFormat == NextPrevFormat.ShortMonth || nextPrevFormat == NextPrevFormat.FullMonth) {
1775                         int monthNo = threadCalendar.GetMonth(threadCalendar.AddMonths(visibleDate, 1));
1776                         nextMonthText = GetMonthName(monthNo, (nextPrevFormat == NextPrevFormat.FullMonth));
1777                     }
1778                     else {
1779                         nextMonthText = NextMonthText;
1780                     }
1781                     // Month navigation. The command starts with a "V" and the remainder is day difference from the
1782                     // base date.
1783                     DateTime nextMonthDate = threadCalendar.AddMonths(visibleDate, 1);
1784                     string nextMonthKey = NAVIGATE_MONTH_COMMAND + (nextMonthDate.Subtract(baseDate)).Days.ToString(CultureInfo.InvariantCulture);
1785
1786                     string nextMonthTitle = null;
1787                     if (useAccessibleHeader) {
1788                         nextMonthTitle = SR.GetString(SR.Calendar_NextMonthTitle);
1789                     }
1790                     RenderCalendarCell(writer, nextPrevStyle, nextMonthText, nextMonthTitle, buttonsActive, nextMonthKey);
1791                 }
1792             }
1793             writer.Write(ROWENDTAG);
1794             titleTable.RenderEndTag(writer);
1795             titleCell.RenderEndTag(writer);
1796             writer.Write(ROWENDTAG);
1797
1798         }
1799
1800
1801         /// <internalonly/>
1802         /// <devdoc>
1803         /// <para>Stores the state of the System.Web.UI.WebControls.Calender.</para>
1804         /// </devdoc>
1805         protected override object SaveViewState() {
1806             if (SelectedDates.Count > 0)
1807                 ViewState["SD"] = dateList;
1808
1809             object[] myState = new object[10];
1810
1811             myState[0] = base.SaveViewState();
1812             myState[1] = (titleStyle != null) ? ((IStateManager)titleStyle).SaveViewState() : null;
1813             myState[2] = (nextPrevStyle != null) ? ((IStateManager)nextPrevStyle).SaveViewState() : null;
1814             myState[3] = (dayStyle != null) ? ((IStateManager)dayStyle).SaveViewState() : null;
1815             myState[4] = (dayHeaderStyle != null) ? ((IStateManager)dayHeaderStyle).SaveViewState() : null;
1816             myState[5] = (todayDayStyle != null) ? ((IStateManager)todayDayStyle).SaveViewState() : null;
1817             myState[6] = (weekendDayStyle != null) ? ((IStateManager)weekendDayStyle).SaveViewState() : null;
1818             myState[7] = (otherMonthDayStyle != null) ? ((IStateManager)otherMonthDayStyle).SaveViewState() : null;
1819             myState[8] = (selectedDayStyle != null) ? ((IStateManager)selectedDayStyle).SaveViewState() : null;
1820             myState[9] = (selectorStyle != null) ? ((IStateManager)selectorStyle).SaveViewState() : null;
1821
1822             for (int i = 0; i<myState.Length; i++) {
1823                 if (myState[i] != null)
1824                     return myState;
1825             }
1826
1827             return null;
1828         }
1829
1830         private void SelectRange(DateTime dateFrom, DateTime dateTo) {
1831
1832             Debug.Assert(dateFrom <= dateTo, "Bad Date Range");
1833
1834             // see if this range differs in any way from the current range
1835             // these checks will determine this because the colleciton is sorted
1836             TimeSpan ts = dateTo - dateFrom;
1837             if (SelectedDates.Count != ts.Days + 1
1838                 || SelectedDates[0] != dateFrom
1839                 || SelectedDates[SelectedDates.Count - 1] != dateTo) {
1840                 SelectedDates.SelectRange(dateFrom, dateTo);
1841                 OnSelectionChanged();
1842             }
1843         }
1844
1845
1846         /// <devdoc>
1847         /// </devdoc>
1848         private void SetDayStyles(TableItemStyle style, int styleMask, Unit defaultWidth) {
1849
1850             // default day styles
1851             style.Width = defaultWidth;
1852             style.HorizontalAlign = HorizontalAlign.Center;
1853
1854             if ((styleMask & STYLEMASK_DAY) != 0) {
1855                 style.CopyFrom(DayStyle);
1856             }
1857             if ((styleMask & STYLEMASK_WEEKEND) != 0) {
1858                 style.CopyFrom(WeekendDayStyle);
1859             }
1860             if ((styleMask & STYLEMASK_OTHERMONTH) != 0) {
1861                 style.CopyFrom(OtherMonthDayStyle);
1862             }
1863             if ((styleMask & STYLEMASK_TODAY) != 0) {
1864                 style.CopyFrom(TodayDayStyle);
1865             }
1866
1867             if ((styleMask & STYLEMASK_SELECTED) != 0) {
1868                 // default selected day style
1869                 style.ForeColor = Color.White;
1870                 style.BackColor = Color.Silver;
1871
1872                 style.CopyFrom(SelectedDayStyle);
1873             }
1874         }
1875     }
1876 }
1877
1878