1 //------------------------------------------------------------------------------
2 // <copyright file="ChtmlCalendarAdapter.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 //------------------------------------------------------------------------------
8 using System.Globalization;
13 using System.Web.UI.HtmlControls;
14 using System.Web.UI.MobileControls;
15 using System.Web.UI.MobileControls.Adapters;
16 using System.Web.UI.WebControls;
17 using System.Diagnostics;
18 using System.Collections;
19 using System.Security.Permissions;
21 #if COMPILING_FOR_SHIPPED_SOURCE
22 namespace System.Web.UI.MobileControls.ShippedAdapterSource
24 namespace System.Web.UI.MobileControls.Adapters
29 * ChtmlCalendarAdapter provides the cHTML device functionality for Calendar
30 * control. It is using secondary UI support to provide internal screens
31 * to allow the user to pick or enter a date.
33 * Copyright (c) 2000 Microsoft Corporation
35 /// <include file='doc\ChtmlCalendarAdapter.uex' path='docs/doc[@for="ChtmlCalendarAdapter"]/*' />
36 [AspNetHostingPermission(SecurityAction.LinkDemand, Level=AspNetHostingPermissionLevel.Minimal)]
37 [AspNetHostingPermission(SecurityAction.InheritanceDemand, Level=AspNetHostingPermissionLevel.Minimal)]
38 [Obsolete("The System.Web.Mobile.dll assembly has been deprecated and should no longer be used. For information about how to develop ASP.NET mobile applications, see http://go.microsoft.com/fwlink/?LinkId=157231.")]
39 public class ChtmlCalendarAdapter : HtmlControlAdapter
41 private SelectionList _selectList;
42 private TextBox _textBox;
43 private Command _command;
44 private List _optionList;
45 private List _monthList;
46 private List _weekList;
47 private List _dayList;
48 private int _chooseOption = FirstPrompt;
49 private int _monthsToDisplay;
50 private int _eraCount = 0;
51 private bool _requireFormTag = false;
53 /////////////////////////////////////////////////////////////////////
54 // Globalization of Calendar Information:
55 // Similar to the globalization support of the ASP.NET Calendar control,
56 // this support is done via COM+ thread culture info/object.
57 // Specific example can be found from ASP.NET Calendar spec.
58 /////////////////////////////////////////////////////////////////////
60 // This member variable is set each time when calendar info needs to
61 // be accessed and be shared for other helper functions.
62 private System.Globalization.Calendar _threadCalendar;
64 private String _textBoxErrorMessage;
66 // Since SecondaryUIMode is an int type, we use constant integers here
67 // instead of enum so the mode can be compared without casting.
68 private const int FirstPrompt = NotSecondaryUIInit;
69 private const int OptionPrompt = NotSecondaryUIInit + 1;
70 private const int TypeDate = NotSecondaryUIInit + 2;
71 private const int DateOption = NotSecondaryUIInit + 3;
72 private const int WeekOption = NotSecondaryUIInit + 4;
73 private const int MonthOption = NotSecondaryUIInit + 5;
74 private const int ChooseMonth = NotSecondaryUIInit + 6;
75 private const int ChooseWeek = NotSecondaryUIInit + 7;
76 private const int ChooseDay = NotSecondaryUIInit + 8;
77 private const int DefaultDateDone = NotSecondaryUIInit + 9;
78 private const int TypeDateDone = NotSecondaryUIInit + 10;
79 private const int Done = NotSecondaryUIInit + 11;
81 private const String DaySeparator = " - ";
82 private const String Space = " ";
84 /// <include file='doc\ChtmlCalendarAdapter.uex' path='docs/doc[@for="ChtmlCalendarAdapter.Control"]/*' />
85 protected new Calendar Control
89 return (Calendar)base.Control;
93 /// <include file='doc\ChtmlCalendarAdapter.uex' path='docs/doc[@for="ChtmlCalendarAdapter.RequiresFormTag"]/*' />
94 public override bool RequiresFormTag
98 return _requireFormTag;
102 /// <include file='doc\ChtmlCalendarAdapter.uex' path='docs/doc[@for="ChtmlCalendarAdapter.OnInit"]/*' />
103 public override void OnInit(EventArgs e)
105 ListCommandEventHandler listCommandEventHandler;
107 // Create secondary child controls for rendering secondary UI.
108 // Note that their ViewState is disabled because they are used
109 // for rendering only.
110 //---------------------------------------------------------------
112 _selectList = new SelectionList();
113 _selectList.Visible = false;
114 _selectList.EnableViewState = false;
115 Control.Controls.Add(_selectList);
117 _textBox = new TextBox();
118 _textBox.Visible = false;
119 _textBox.EnableViewState = false;
120 EventHandler eventHandler = new EventHandler(this.TextBoxEventHandler);
121 _textBox.TextChanged += eventHandler;
122 Control.Controls.Add(_textBox);
124 _command = new Command();
125 _command.Visible = false;
126 _command.EnableViewState = false;
127 Control.Controls.Add(_command);
129 // Below are initialization of several list controls. A note is
130 // that here the usage of DataMember is solely for remembering
131 // how many items a particular list control is bounded to. The
132 // property is not used as originally designed.
133 //---------------------------------------------------------------
135 _optionList = new List();
136 _optionList.DataMember = "5";
137 listCommandEventHandler = new ListCommandEventHandler(this.OptionListEventHandler);
138 InitList(_optionList, listCommandEventHandler);
140 // Use MobileCapabilities to check screen size and determine how
141 // many months should be displayed for different devices.
142 _monthsToDisplay = MonthsToDisplay(Device.ScreenCharactersHeight);
144 // Create the list of months, including [Next] and [Prev] links
145 _monthList = new List();
146 _monthList.DataMember = Convert.ToString(_monthsToDisplay + 2, CultureInfo.InvariantCulture);
147 listCommandEventHandler = new ListCommandEventHandler(this.MonthListEventHandler);
148 InitList(_monthList, listCommandEventHandler);
150 _weekList = new List();
151 _weekList.DataMember = "6";
152 listCommandEventHandler = new ListCommandEventHandler(this.WeekListEventHandler);
153 InitList(_weekList, listCommandEventHandler);
155 _dayList = new List();
156 _dayList.DataMember = "7";
157 listCommandEventHandler = new ListCommandEventHandler(this.DayListEventHandler);
158 InitList(_dayList, listCommandEventHandler);
160 // Initialize the VisibleDate which will be used to keep track
161 // the ongoing selection of year, month and day from multiple
162 // secondary UI screens. If the page is loaded for the first
163 // time, it doesn't need to be initialized (since it is not used
164 // yet) so no unnecessary viewstate value will be generated.
165 if (Page.IsPostBack && Control.VisibleDate == DateTime.MinValue)
167 Control.VisibleDate = DateTime.Today;
171 /// <include file='doc\ChtmlCalendarAdapter.uex' path='docs/doc[@for="ChtmlCalendarAdapter.OnLoad"]/*' />
172 public override void OnLoad(EventArgs e)
176 // Here we check to see which list control should be initialized
177 // with items so postback event can be handled properly.
180 String controlId = Page.Request[Constants.EventSourceID];
181 if (controlId != null && controlId.Length != 0)
183 List list = Page.FindControl(controlId) as List;
185 Control.Controls.Contains(list))
187 DataBindListWithEmptyValues(
188 list, Convert.ToInt32(list.DataMember, CultureInfo.InvariantCulture));
194 /// <include file='doc\ChtmlCalendarAdapter.uex' path='docs/doc[@for="ChtmlCalendarAdapter.LoadAdapterState"]/*' />
195 public override void LoadAdapterState(Object state)
201 Pair pair = (Pair)state;
202 base.LoadAdapterState(pair.First);
203 _chooseOption = (int)pair.Second;
205 else if (state is Triplet)
207 Triplet triplet = (Triplet)state;
208 base.LoadAdapterState(triplet.First);
209 _chooseOption = (int)triplet.Second;
210 Control.VisibleDate = new DateTime(Int64.Parse((String)triplet.Third, CultureInfo.InvariantCulture));
212 else if (state is Object[])
214 Object[] viewState = (Object[])state;
215 base.LoadAdapterState(viewState[0]);
216 _chooseOption = (int)viewState[1];
217 Control.VisibleDate = new DateTime(Int64.Parse((String)viewState[2], CultureInfo.InvariantCulture));
218 _eraCount = (int)viewState[3];
220 if (SecondaryUIMode == TypeDate)
222 // Create a placeholder list for capturing the selected era
224 for (int i = 0; i < _eraCount; i++)
226 _selectList.Items.Add(String.Empty);
232 _chooseOption = (int)state;
237 /// <include file='doc\ChtmlCalendarAdapter.uex' path='docs/doc[@for="ChtmlCalendarAdapter.SaveAdapterState"]/*' />
238 public override Object SaveAdapterState()
240 DateTime visibleDate = Control.VisibleDate;
242 bool saveVisibleDate = visibleDate != DateTime.MinValue &&
243 DateTime.Compare(visibleDate, DateTime.Today) != 0 &&
244 !IsViewStateEnabled();
245 Object baseState = base.SaveAdapterState();
247 if (baseState == null && !saveVisibleDate && _eraCount == 0)
249 if (_chooseOption != FirstPrompt)
251 return _chooseOption;
258 else if (!saveVisibleDate && _eraCount == 0)
260 return new Pair(baseState, _chooseOption);
262 else if (_eraCount == 0)
264 return new Triplet(baseState, _chooseOption, visibleDate.Ticks.ToString(CultureInfo.InvariantCulture));
268 return new Object[] { baseState,
270 visibleDate.Ticks.ToString(CultureInfo.InvariantCulture),
275 /// <include file='doc\ChtmlCalendarAdapter.uex' path='docs/doc[@for="ChtmlCalendarAdapter.OnPreRender"]/*' />
276 public override void OnPreRender(EventArgs e)
280 // We specially binding eras of the current calendar object here
281 // when the UI of typing date is display. We do it only if the
282 // calendar supports more than one era.
283 if (SecondaryUIMode == TypeDate)
285 DateTimeFormatInfo currentInfo = DateTimeFormatInfo.CurrentInfo;
287 int [] ints = currentInfo.Calendar.Eras;
291 // Save the value in private view state
292 _eraCount = ints.Length;
295 if (_selectList.SelectedIndex != -1)
297 currentEra = ints[_selectList.SelectedIndex];
302 currentInfo.Calendar.GetEra(Control.VisibleDate);
305 // Clear the placeholder item list if created in LoadAdapterState
306 _selectList.Items.Clear();
308 for (int i = 0; i < ints.Length; i++)
312 _selectList.Items.Add(currentInfo.GetEraName(era));
314 // There is no association between the era value and
315 // its index in the era array, so we need to check it
316 // explicitly for the default selected index.
317 if (currentEra == era)
319 _selectList.SelectedIndex = i;
322 _selectList.Visible = true;
326 // disable viewstate since no need to save any data for
328 _selectList.EnableViewState = false;
333 _selectList.EnableViewState = false;
337 /// <include file='doc\ChtmlCalendarAdapter.uex' path='docs/doc[@for="ChtmlCalendarAdapter.Render"]/*' />
338 public override void Render(HtmlMobileTextWriter writer)
342 DateTimeFormatInfo currentDateTimeInfo = DateTimeFormatInfo.CurrentInfo;
343 String abbreviatedMonthDayPattern = AbbreviateMonthPattern(currentDateTimeInfo.MonthDayPattern);
344 _threadCalendar = currentDateTimeInfo.Calendar;
345 bool breakAfter = false;
347 writer.EnterStyle(Style);
349 Debug.Assert(NotSecondaryUI == NotSecondaryUIInit);
350 switch (SecondaryUIMode)
353 String promptText = Control.CalendarEntryText;
354 if (String.IsNullOrEmpty(promptText))
356 promptText = SR.GetString(SR.CalendarAdapterFirstPrompt);
359 // Link to input option selection screen
360 RenderPostBackEventAsAnchor(writer,
361 OptionPrompt.ToString(CultureInfo.InvariantCulture),
364 // We should honor BreakAfter property here as the first
365 // UI is shown with other controls on the same form.
366 // For other secondary UI, it is not necessary.
367 if (Control.BreakAfter)
373 // Render the first secondary page that provides differnt
374 // options to select a date.
376 writer.Write(SR.GetString(SR.CalendarAdapterOptionPrompt));
379 arr = new ArrayList();
381 // Option to select the default date
382 arr.Add(Control.VisibleDate.ToString(
383 currentDateTimeInfo.ShortDatePattern, CultureInfo.CurrentCulture));
385 // Option to another page that can enter a date by typing
386 arr.Add(SR.GetString(SR.CalendarAdapterOptionType));
388 // Options to a set of pages for selecting a date, a week
389 // or a month by picking month/year, week and day
390 // accordingly. Available options are determined by
392 arr.Add(SR.GetString(SR.CalendarAdapterOptionChooseDate));
394 if (Control.SelectionMode == CalendarSelectionMode.DayWeek ||
395 Control.SelectionMode == CalendarSelectionMode.DayWeekMonth)
397 arr.Add(SR.GetString(SR.CalendarAdapterOptionChooseWeek));
399 if (Control.SelectionMode == CalendarSelectionMode.DayWeekMonth)
401 arr.Add(SR.GetString(SR.CalendarAdapterOptionChooseMonth));
405 DataBindAndRender(writer, _optionList, arr);
408 // Render a title and textbox to capture a date entered by user
410 if (_textBoxErrorMessage != null)
412 writer.Write(_textBoxErrorMessage);
416 if (_selectList.Visible)
418 writer.Write(SR.GetString(SR.CalendarAdapterOptionEra));
420 _selectList.RenderControl(writer);
423 String numericDateFormat = GetNumericDateFormat();
425 writer.Write(SR.GetString(SR.CalendarAdapterOptionType));
429 writer.Write(numericDateFormat.ToUpper(CultureInfo.InvariantCulture));
432 if (!_selectList.Visible)
434 writer.Write(GetEra(Control.VisibleDate));
438 _textBox.Numeric = true;
439 _textBox.Size = numericDateFormat.Length;
440 _textBox.MaxLength = numericDateFormat.Length;
441 _textBox.Text = Control.VisibleDate.ToString(numericDateFormat, CultureInfo.InvariantCulture);
442 _textBox.Visible = true;
443 _textBox.RenderControl(writer);
445 // Command button for sending the textbox value back to the server
446 _command.Text = GetDefaultLabel(OKLabel);
447 _command.Visible = true;
448 _command.RenderControl(writer);
452 // Render a paged list for choosing a month
454 writer.Write(SR.GetString(SR.CalendarAdapterOptionChooseMonth));
458 tempDate = Control.VisibleDate;
460 String abbreviatedYearMonthPattern = AbbreviateMonthPattern(currentDateTimeInfo.YearMonthPattern);
462 // This is to be consistent with ASP.NET Calendar control
463 // on handling YearMonthPattern:
464 // Some cultures have a comma in their YearMonthPattern,
465 // which does not look right in a calendar. Here we
466 // strip the comma off.
467 int indexComma = abbreviatedYearMonthPattern.IndexOf(',');
470 abbreviatedYearMonthPattern =
471 abbreviatedYearMonthPattern.Remove(indexComma, 1);
474 arr = new ArrayList();
475 for (int i = 0; i < _monthsToDisplay; i++)
477 arr.Add(tempDate.ToString(abbreviatedYearMonthPattern, CultureInfo.CurrentCulture));
478 tempDate = _threadCalendar.AddMonths(tempDate, 1);
480 arr.Add(GetDefaultLabel(NextLabel));
481 arr.Add(GetDefaultLabel(PreviousLabel));
483 DataBindAndRender(writer, _monthList, arr);
486 // Based on the month selected in case ChooseMonth above, render a list of
487 // availabe weeks of the month.
489 String monthFormat = (GetNumericDateFormat()[0] == 'y') ? "yyyy/M" : "M/yyyy";
490 writer.Write(SR.GetString(SR.CalendarAdapterOptionChooseWeek));
492 writer.Write(Control.VisibleDate.ToString(monthFormat, CultureInfo.CurrentCulture));
496 // List weeks of days of the selected month. May include
497 // days from the previous and the next month to fill out
498 // all six week choices. This is consistent with the
499 // ASP.NET Calendar control.
501 // Note that the event handling code of this list control
502 // should be implemented according to the index content
505 tempDate = FirstCalendarDay(Control.VisibleDate);
507 arr = new ArrayList();
509 for (int i = 0; i < 6; i++)
511 weekDisplay = tempDate.ToString(abbreviatedMonthDayPattern, CultureInfo.CurrentCulture);
512 weekDisplay += DaySeparator;
513 tempDate = _threadCalendar.AddDays(tempDate, 6);
514 weekDisplay += tempDate.ToString(abbreviatedMonthDayPattern, CultureInfo.CurrentCulture);
515 arr.Add(weekDisplay);
516 tempDate = _threadCalendar.AddDays(tempDate, 1);
519 DataBindAndRender(writer, _weekList, arr);
522 // Based on the month and week selected in case ChooseMonth and ChooseWeek above,
523 // render a list of the dates in the week.
525 writer.Write(SR.GetString(SR.CalendarAdapterOptionChooseDate));
529 tempDate = Control.VisibleDate;
531 arr = new ArrayList();
534 StringBuilder dayDisplay = new StringBuilder();
535 bool dayNameFirst = (GetNumericDateFormat()[0] != 'y');
537 for (int i = 0; i < 7; i++)
539 date = tempDate.ToString(abbreviatedMonthDayPattern, CultureInfo.CurrentCulture);
541 if (Control.ShowDayHeader)
543 // Use the short format for displaying day name
544 dayName = GetAbbreviatedDayName(tempDate);
545 dayDisplay.Length = 0;
549 dayDisplay.Append(dayName);
550 dayDisplay.Append(Space);
551 dayDisplay.Append(date);
555 dayDisplay.Append(date);
556 dayDisplay.Append(Space);
557 dayDisplay.Append(dayName);
559 arr.Add(dayDisplay.ToString());
565 tempDate = _threadCalendar.AddDays(tempDate, 1);
568 DataBindAndRender(writer, _dayList, arr);
572 Debug.Assert(false, "Unexpected Secondary UI Mode");
576 writer.ExitStyle(Style, breakAfter);
579 /// <include file='doc\ChtmlCalendarAdapter.uex' path='docs/doc[@for="ChtmlCalendarAdapter.HandlePostBackEvent"]/*' />
580 public override bool HandlePostBackEvent(String eventArgument)
582 // This is mainly to capture the option picked by the user on
583 // secondary pages and manipulate SecondaryUIMode accordingly so
584 // Render() can generate the appropriate UI.
585 // It also capture the state "Done" which can be set when a date,
586 // a week or a month is selected or entered in some secondary
589 SecondaryUIMode = Int32.Parse(eventArgument, CultureInfo.InvariantCulture);
591 Debug.Assert(NotSecondaryUI == NotSecondaryUIInit);
592 switch (SecondaryUIMode)
594 case DefaultDateDone:
595 SelectRange(Control.VisibleDate, Control.VisibleDate);
599 _requireFormTag = true;
605 String dateText = _textBox.Text;
606 String dateFormat = GetNumericDateFormat();
607 DateTimeFormatInfo currentInfo = DateTimeFormatInfo.CurrentInfo;
608 int eraIndex = _selectList.SelectedIndex;
611 eraIndex < currentInfo.Calendar.Eras.Length)
613 dateText += currentInfo.GetEraName(currentInfo.Calendar.Eras[eraIndex]);
617 DateTime dateTime = DateTime.ParseExact(dateText, dateFormat, null);
618 SelectRange(dateTime, dateTime);
619 Control.VisibleDate = dateTime;
623 _textBoxErrorMessage = SR.GetString(SR.CalendarAdapterTextBoxErrorMessage);
624 SecondaryUIMode = TypeDate;
630 // Set the secondary exit code and raise the selection event for
631 // web page developer to manipulate the selected date.
632 ExitSecondaryUIMode();
633 _chooseOption = FirstPrompt;
639 _chooseOption = SecondaryUIMode; // save in the ViewState
641 // In all 3 cases, continue to the UI that chooses a month
642 SecondaryUIMode = ChooseMonth;
649 /////////////////////////////////////////////////////////////////////
650 // Misc. helper and wrapper functions
651 /////////////////////////////////////////////////////////////////////
653 private int MonthsToDisplay(int screenCharactersHeight)
655 const int MinMonthsToDisplay = 4;
656 const int MaxMonthsToDisplay = 12;
658 if (screenCharactersHeight < MinMonthsToDisplay)
660 return MinMonthsToDisplay;
662 else if (screenCharactersHeight > MaxMonthsToDisplay)
664 return MaxMonthsToDisplay;
666 return screenCharactersHeight;
669 // A helper function to initialize and add a child list control
670 private void InitList(List list,
671 ListCommandEventHandler eventHandler)
673 list.Visible = false;
674 list.ItemCommand += eventHandler;
675 list.EnableViewState = false;
676 Control.Controls.Add(list);
679 private void DataBindListWithEmptyValues(List list, int arraySize)
681 ArrayList arr = new ArrayList();
682 for (int i = 0; i < arraySize; i++)
686 list.DataSource = arr;
690 // A helper function to do the common code for DataBind and
692 private void DataBindAndRender(HtmlMobileTextWriter writer,
696 list.DataSource = arr;
699 list.RenderControl(writer);
702 // Abbreviate the Month format from "MMMM" (full
703 // month name) to "MMM" (three-character month abbreviation)
704 private String AbbreviateMonthPattern(String pattern)
706 const String FullMonthFormat = "MMMM";
708 int i = pattern.IndexOf(FullMonthFormat, StringComparison.Ordinal);
711 pattern = pattern.Remove(i, 1);
716 private String GetAbbreviatedDayName(DateTime dateTime)
718 return DateTimeFormatInfo.CurrentInfo.GetAbbreviatedDayName(
719 _threadCalendar.GetDayOfWeek(dateTime));
722 private String GetEra(DateTime dateTime)
724 // We shouldn't need to display the era for the common Gregorian
726 if (DateTimeFormatInfo.CurrentInfo.Calendar.GetType() ==
727 typeof(GregorianCalendar))
733 return dateTime.ToString("gg", CultureInfo.CurrentCulture);
737 private static readonly char[] formatChars =
738 new char[] { 'M', 'd', 'y' };
740 private String GetNumericDateFormat()
742 String shortDatePattern =
743 DateTimeFormatInfo.CurrentInfo.ShortDatePattern;
745 // Guess on what short date pattern should be used
746 int i = shortDatePattern.IndexOfAny(formatChars);
748 char firstFormatChar;
751 firstFormatChar = 'M';
755 firstFormatChar = shortDatePattern[i];
758 // We either use two or four digits for the year
760 if (shortDatePattern.IndexOf("yyyy", StringComparison.Ordinal) == -1)
766 yearPattern = "yyyy";
769 switch (firstFormatChar)
773 return "MMdd" + yearPattern;
775 return "ddMM" + yearPattern;
777 return yearPattern + "MMdd";
781 /////////////////////////////////////////////////////////////////////
783 /////////////////////////////////////////////////////////////////////
785 // Return the first date of the input year and month
786 private DateTime EffectiveVisibleDate(DateTime visibleDate)
788 return _threadCalendar.AddDays(
790 -(_threadCalendar.GetDayOfMonth(visibleDate) - 1));
793 // Return the beginning date of a calendar that includes the
794 // targeting month. The date can actually be in the previous month.
795 private DateTime FirstCalendarDay(DateTime visibleDate)
797 DateTime firstDayOfMonth = EffectiveVisibleDate(visibleDate);
798 int daysFromLastMonth =
799 ((int)_threadCalendar.GetDayOfWeek(firstDayOfMonth)) -
800 NumericFirstDayOfWeek();
802 // Always display at least one day from the previous month
803 if (daysFromLastMonth <= 0)
805 daysFromLastMonth += 7;
807 return _threadCalendar.AddDays(firstDayOfMonth, -daysFromLastMonth);
810 private int NumericFirstDayOfWeek()
812 // Used globalized value by default
813 return(Control.FirstDayOfWeek == FirstDayOfWeek.Default)
814 ? (int) DateTimeFormatInfo.CurrentInfo.FirstDayOfWeek
815 : (int) Control.FirstDayOfWeek;
818 /////////////////////////////////////////////////////////////////////
819 // The followings are event handlers to capture the selection from
820 // the corresponding list control in an secondary page. The index of
821 // the selection is used to determine which and how the next
822 // secondary page is rendered. Some event handlers below update
823 // Calendar.VisibleDate and set SecondaryUIMode with appropriate
825 ////////////////////////////////////////////////////////////////////////
827 private void TextBoxEventHandler(Object source, EventArgs e)
829 HandlePostBackEvent(TypeDateDone.ToString(CultureInfo.InvariantCulture));
832 private static readonly int[] Options =
833 {DefaultDateDone, TypeDate, DateOption, WeekOption, MonthOption};
835 private void OptionListEventHandler(Object source, ListCommandEventArgs e)
837 SecondaryUIMode = Options[e.ListItem.Index];
838 HandlePostBackEvent(SecondaryUIMode.ToString(CultureInfo.InvariantCulture));
841 private void MonthListEventHandler(Object source, ListCommandEventArgs e)
843 _threadCalendar = DateTimeFormatInfo.CurrentInfo.Calendar;
845 if (e.ListItem.Index == _monthsToDisplay)
848 Control.VisibleDate = _threadCalendar.AddMonths(
849 Control.VisibleDate, _monthsToDisplay);
850 SecondaryUIMode = ChooseMonth;
852 else if (e.ListItem.Index == _monthsToDisplay + 1)
855 Control.VisibleDate = _threadCalendar.AddMonths(
856 Control.VisibleDate, -_monthsToDisplay);
857 SecondaryUIMode = ChooseMonth;
861 // A month was selected
862 Control.VisibleDate = _threadCalendar.AddMonths(
866 if (_chooseOption == MonthOption)
868 // Add the whole month to the date list
869 DateTime beginDate = EffectiveVisibleDate(Control.VisibleDate);
870 Control.VisibleDate = beginDate;
872 DateTime endDate = _threadCalendar.AddMonths(beginDate, 1);
873 endDate = _threadCalendar.AddDays(endDate, -1);
875 SelectRange(beginDate, endDate);
876 HandlePostBackEvent(Done.ToString(CultureInfo.InvariantCulture));
880 SecondaryUIMode = ChooseWeek;
885 private void WeekListEventHandler(Object source, ListCommandEventArgs e)
887 // Get the first calendar day and adjust it to the week the user
888 // selected (to be consistent with the index setting in Render())
889 _threadCalendar = DateTimeFormatInfo.CurrentInfo.Calendar;
891 DateTime tempDate = FirstCalendarDay(Control.VisibleDate);
893 Control.VisibleDate = _threadCalendar.AddDays(tempDate, e.ListItem.Index * 7);
895 if (_chooseOption == WeekOption)
897 // Add the whole week to the date list
898 DateTime endDate = _threadCalendar.AddDays(Control.VisibleDate, 6);
900 SelectRange(Control.VisibleDate, endDate);
901 HandlePostBackEvent(Done.ToString(CultureInfo.InvariantCulture));
905 SecondaryUIMode = ChooseDay;
909 private void DayListEventHandler(Object source, ListCommandEventArgs e)
911 _threadCalendar = DateTimeFormatInfo.CurrentInfo.Calendar;
913 // VisibleDate should have been set with the first day of the week
914 // so the selected index can be used to adjust to the selected day.
915 Control.VisibleDate = _threadCalendar.AddDays(Control.VisibleDate, e.ListItem.Index);
917 SelectRange(Control.VisibleDate, Control.VisibleDate);
918 HandlePostBackEvent(Done.ToString(CultureInfo.InvariantCulture));
921 private void SelectRange(DateTime dateFrom, DateTime dateTo)
923 Debug.Assert(dateFrom <= dateTo, "Bad Date Range");
925 // see if this range differs in any way from the current range
926 // these checks will determine this because the colleciton is sorted
927 TimeSpan ts = dateTo - dateFrom;
928 SelectedDatesCollection selectedDates = Control.SelectedDates;
929 if (selectedDates.Count != ts.Days + 1
930 || selectedDates[0] != dateFrom
931 || selectedDates[selectedDates.Count - 1] != dateTo)
933 selectedDates.SelectRange(dateFrom, dateTo);
934 Control.RaiseSelectionChangedEvent();
938 private bool IsViewStateEnabled()
940 Control ctl = Control;
943 if (!ctl.EnableViewState)