1 //------------------------------------------------------------------------------
2 // <copyright file="WmlCalendarAdapter.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 * WmlCalendarAdapter provides the wml 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\WmlCalendarAdapter.uex' path='docs/doc[@for="WmlCalendarAdapter"]/*' />
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 WmlCalendarAdapter : WmlControlAdapter
41 private SelectionList _selectList;
42 private TextBox _textBox;
43 private List _optionList;
44 private List _monthList;
45 private List _weekList;
46 private List _dayList;
47 private int _chooseOption = FirstPrompt;
48 private int _monthsToDisplay;
49 private int _eraCount = 0;
51 /////////////////////////////////////////////////////////////////////
52 // Globalization of Calendar Information:
53 // Similar to the globalization support of the ASP.NET Calendar control,
54 // this support is done via COM+ thread culture info/object.
55 // Specific example can be found from ASP.NET Calendar spec.
56 /////////////////////////////////////////////////////////////////////
58 // This member variable is set each time when calendar info needs to
59 // be accessed and be shared for other helper functions.
60 private Globalization.Calendar _threadCalendar;
62 private String _textBoxErrorMessage;
64 // Since SecondaryUIMode is an int type, we use constant integers here
65 // instead of enum so the mode can be compared without casting.
66 private const int FirstPrompt = NotSecondaryUIInit;
67 private const int OptionPrompt = NotSecondaryUIInit + 1;
68 private const int TypeDate = NotSecondaryUIInit + 2;
69 private const int DateOption = NotSecondaryUIInit + 3;
70 private const int WeekOption = NotSecondaryUIInit + 4;
71 private const int MonthOption = NotSecondaryUIInit + 5;
72 private const int ChooseMonth = NotSecondaryUIInit + 6;
73 private const int ChooseWeek = NotSecondaryUIInit + 7;
74 private const int ChooseDay = NotSecondaryUIInit + 8;
75 private const int DefaultDateDone = NotSecondaryUIInit + 9;
76 private const int TypeDateDone = NotSecondaryUIInit + 10;
77 private const int Done = NotSecondaryUIInit + 11;
79 private const String DaySeparator = " - ";
80 private const String Space = " ";
82 /// <include file='doc\WmlCalendarAdapter.uex' path='docs/doc[@for="WmlCalendarAdapter.Control"]/*' />
83 protected new Calendar Control
87 return (Calendar)base.Control;
91 /// <include file='doc\WmlCalendarAdapter.uex' path='docs/doc[@for="WmlCalendarAdapter.OnInit"]/*' />
92 public override void OnInit(EventArgs e)
94 ListCommandEventHandler listCommandEventHandler;
96 // Create secondary child controls for rendering secondary UI.
97 // Note that their ViewState is disabled because they are used
98 // for rendering only.
99 //---------------------------------------------------------------
101 _selectList = new SelectionList();
102 _selectList.Visible = false;
103 _selectList.EnableViewState = false;
104 Control.Controls.Add(_selectList);
106 _textBox = new TextBox();
107 _textBox.Visible = false;
108 _textBox.EnableViewState = false;
109 Control.Controls.Add(_textBox);
111 // Below are initialization of several list controls. A note is
112 // that here the usage of DataMember is solely for remembering
113 // how many items a particular list control is bounded to. The
114 // property is not used as originally designed.
115 //---------------------------------------------------------------
117 _optionList = new List();
118 _optionList.DataMember = "5";
119 listCommandEventHandler = new ListCommandEventHandler(this.OptionListEventHandler);
120 InitList(_optionList, listCommandEventHandler);
122 // Use MobileCapabilities to check screen size and determine how
123 // many months should be displayed for different devices.
124 _monthsToDisplay = MonthsToDisplay(Device.ScreenCharactersHeight);
126 // Create the list of months, including [Next] and [Prev] links
127 _monthList = new List();
128 _monthList.DataMember = Convert.ToString(_monthsToDisplay + 2, CultureInfo.InvariantCulture);
129 listCommandEventHandler = new ListCommandEventHandler(this.MonthListEventHandler);
130 InitList(_monthList, listCommandEventHandler);
132 _weekList = new List();
133 _weekList.DataMember = "6";
134 listCommandEventHandler = new ListCommandEventHandler(this.WeekListEventHandler);
135 InitList(_weekList, listCommandEventHandler);
137 _dayList = new List();
138 _dayList.DataMember = "7";
139 listCommandEventHandler = new ListCommandEventHandler(this.DayListEventHandler);
140 InitList(_dayList, listCommandEventHandler);
142 // Initialize the VisibleDate which will be used to keep track
143 // the ongoing selection of year, month and day from multiple
144 // secondary UI screens. If the page is loaded for the first
145 // time, it doesn't need to be initialized (since it is not used
146 // yet) so no unnecessary viewstate value will be generated.
147 if (Page.IsPostBack && Control.VisibleDate == DateTime.MinValue)
149 Control.VisibleDate = DateTime.Today;
153 /// <include file='doc\WmlCalendarAdapter.uex' path='docs/doc[@for="WmlCalendarAdapter.OnLoad"]/*' />
154 public override void OnLoad(EventArgs e)
158 // Here we check to see which list control should be initialized
159 // with items so postback event can be handled properly.
162 String controlId = Page.Request[MobilePage.HiddenPostEventSourceId];
163 if (controlId != null && controlId.Length != 0)
165 List list = Page.FindControl(controlId) as List;
167 Control.Controls.Contains(list))
169 DataBindListWithEmptyValues(
170 list, Convert.ToInt32(list.DataMember, CultureInfo.InvariantCulture));
176 /// <include file='doc\WmlCalendarAdapter.uex' path='docs/doc[@for="WmlCalendarAdapter.LoadAdapterState"]/*' />
177 public override void LoadAdapterState(Object state)
183 Pair pair = (Pair)state;
184 base.LoadAdapterState(pair.First);
185 _chooseOption = (int)pair.Second;
187 else if (state is Triplet)
189 Triplet triplet = (Triplet)state;
190 base.LoadAdapterState(triplet.First);
191 _chooseOption = (int)triplet.Second;
192 Control.VisibleDate = new DateTime(Int64.Parse((String)triplet.Third, CultureInfo.InvariantCulture));
194 else if (state is Object[])
196 Object[] viewState = (Object[])state;
197 base.LoadAdapterState(viewState[0]);
198 _chooseOption = (int)viewState[1];
199 Control.VisibleDate = new DateTime(Int64.Parse((String)viewState[2], CultureInfo.InvariantCulture));
200 _eraCount = (int)viewState[3];
202 if (SecondaryUIMode == TypeDate)
204 // Create a placeholder list for capturing the selected era
206 for (int i = 0; i < _eraCount; i++)
208 _selectList.Items.Add(String.Empty);
214 _chooseOption = (int)state;
219 /// <include file='doc\WmlCalendarAdapter.uex' path='docs/doc[@for="WmlCalendarAdapter.SaveAdapterState"]/*' />
220 public override Object SaveAdapterState()
222 DateTime visibleDate = Control.VisibleDate;
224 bool saveVisibleDate = visibleDate != DateTime.MinValue &&
225 DateTime.Compare(visibleDate, DateTime.Today) != 0 &&
226 !IsViewStateEnabled();
227 Object baseState = base.SaveAdapterState();
229 if (baseState == null && !saveVisibleDate && _eraCount == 0)
231 if (_chooseOption != FirstPrompt)
233 return _chooseOption;
241 else if (!saveVisibleDate && _eraCount == 0)
243 return new Pair(baseState, _chooseOption);
245 else if (_eraCount == 0)
247 return new Triplet(baseState, _chooseOption, visibleDate.Ticks.ToString(CultureInfo.InvariantCulture));
251 return new Object[] { baseState,
253 visibleDate.Ticks.ToString(CultureInfo.InvariantCulture),
258 /// <include file='doc\WmlCalendarAdapter.uex' path='docs/doc[@for="WmlCalendarAdapter.OnPreRender"]/*' />
259 public override void OnPreRender(EventArgs e)
263 // We specially binding eras of the current calendar object here
264 // when the UI of typing date is display. We do it only if the
265 // calendar supports more than one era.
266 if (SecondaryUIMode == TypeDate)
268 DateTimeFormatInfo currentInfo = DateTimeFormatInfo.CurrentInfo;
270 int [] ints = currentInfo.Calendar.Eras;
274 // Save the value in private view state
275 _eraCount = ints.Length;
278 if (_selectList.SelectedIndex != -1)
280 currentEra = ints[_selectList.SelectedIndex];
285 currentInfo.Calendar.GetEra(Control.VisibleDate);
288 // Clear the placeholder item list if created in LoadAdapterState
289 _selectList.Items.Clear();
291 for (int i = 0; i < ints.Length; i++)
295 _selectList.Items.Add(currentInfo.GetEraName(era));
297 // There is no association between the era value and
298 // its index in the era array, so we need to check it
299 // explicitly for the default selected index.
300 if (currentEra == era)
302 _selectList.SelectedIndex = i;
305 _selectList.Visible = true;
309 // disable viewstate since no need to save any data for
311 _selectList.EnableViewState = false;
316 _selectList.EnableViewState = false;
320 /// <include file='doc\WmlCalendarAdapter.uex' path='docs/doc[@for="WmlCalendarAdapter.Render"]/*' />
321 public override void Render(WmlMobileTextWriter writer)
325 DateTimeFormatInfo currentDateTimeInfo = DateTimeFormatInfo.CurrentInfo;
326 String abbreviatedMonthDayPattern = AbbreviateMonthPattern(currentDateTimeInfo.MonthDayPattern);
327 _threadCalendar = currentDateTimeInfo.Calendar;
329 // RendersWmlSelectsAsMenuCards is true means the list control will be
330 // rendered as select/option tags, where the break tag before
331 // them will become an extra line which doesn't like good.
332 bool addBreakBeforeListControl = Device.RendersWmlSelectsAsMenuCards;
334 writer.EnterStyle(Style);
336 Debug.Assert(NotSecondaryUI == NotSecondaryUIInit);
337 switch (SecondaryUIMode)
340 String promptText = Control.CalendarEntryText;
341 if (String.IsNullOrEmpty(promptText))
343 promptText = SR.GetString(SR.CalendarAdapterFirstPrompt);
346 // Link to input option selection screen
347 RenderPostBackEvent(writer,
348 OptionPrompt.ToString(CultureInfo.InvariantCulture),
349 GetDefaultLabel(GoLabel),
355 // Render the first secondary page that provides differnt
356 // options to select a date.
358 writer.RenderText(SR.GetString(SR.CalendarAdapterOptionPrompt),
359 !addBreakBeforeListControl);
361 arr = new ArrayList();
363 // Option to select the default date
364 arr.Add(Control.VisibleDate.ToString(
365 currentDateTimeInfo.ShortDatePattern, CultureInfo.CurrentCulture));
367 // Option to another page that can enter a date by typing
368 arr.Add(SR.GetString(SR.CalendarAdapterOptionType));
370 // Options to a set of pages for selecting a date, a week
371 // or a month by picking month/year, week and day
372 // accordingly. Available options are determined by
374 arr.Add(SR.GetString(SR.CalendarAdapterOptionChooseDate));
376 if (Control.SelectionMode == CalendarSelectionMode.DayWeek ||
377 Control.SelectionMode == CalendarSelectionMode.DayWeekMonth)
379 arr.Add(SR.GetString(SR.CalendarAdapterOptionChooseWeek));
381 if (Control.SelectionMode == CalendarSelectionMode.DayWeekMonth)
383 arr.Add(SR.GetString(SR.CalendarAdapterOptionChooseMonth));
386 DataBindAndRender(writer, _optionList, arr);
389 // Render a title and textbox to capture a date entered by user
391 if (_textBoxErrorMessage != null)
393 writer.RenderText(_textBoxErrorMessage, true);
396 if (_selectList.Visible)
398 writer.RenderText(SR.GetString(SR.CalendarAdapterOptionEra), true);
399 _selectList.RenderControl(writer);
402 String numericDateFormat = GetNumericDateFormat();
404 writer.RenderText(SR.GetString(SR.CalendarAdapterOptionType) + ":", true);
405 writer.RenderText("(");
406 writer.RenderText(numericDateFormat.ToUpper(CultureInfo.InvariantCulture));
407 writer.RenderText(")");
409 if (!_selectList.Visible)
411 writer.RenderText(GetEra(Control.VisibleDate));
413 writer.RenderText(String.Empty, true);
415 _textBox.Numeric = true;
416 _textBox.Size = numericDateFormat.Length;
417 _textBox.MaxLength = numericDateFormat.Length;
418 _textBox.Text = Control.VisibleDate.ToString(numericDateFormat, CultureInfo.InvariantCulture);
419 _textBox.Visible = true;
420 _textBox.RenderControl(writer);
422 String okLabel = GetDefaultLabel(OKLabel);
424 // accept softkey for sending the textbox value back to the server
425 RenderPostBackEvent(writer,
426 TypeDateDone.ToString(CultureInfo.InvariantCulture),
431 WmlPostFieldType.Raw);
434 // Render a paged list for choosing a month
437 String displayText = String.Format(CultureInfo.CurrentCulture, "{0}:", SR.GetString(SR.CalendarAdapterOptionChooseMonth));
438 writer.RenderText(displayText, !addBreakBeforeListControl);
440 tempDate = Control.VisibleDate;
442 String abbreviatedYearMonthPattern = AbbreviateMonthPattern(currentDateTimeInfo.YearMonthPattern);
444 // This is to be consistent with ASP.NET Calendar control
445 // on handling YearMonthPattern:
446 // Some cultures have a comma in their YearMonthPattern,
447 // which does not look right in a calendar. Here we
448 // strip the comma off.
449 int indexComma = abbreviatedYearMonthPattern.IndexOf(',');
452 abbreviatedYearMonthPattern =
453 abbreviatedYearMonthPattern.Remove(indexComma, 1);
456 arr = new ArrayList();
457 for (int i = 0; i < _monthsToDisplay; i++)
459 arr.Add(tempDate.ToString(abbreviatedYearMonthPattern, CultureInfo.CurrentCulture));
460 tempDate = _threadCalendar.AddMonths(tempDate, 1);
462 arr.Add(GetDefaultLabel(NextLabel));
463 arr.Add(GetDefaultLabel(PreviousLabel));
464 DataBindAndRender(writer, _monthList, arr);
468 // Based on the month selected in case ChooseMonth above, render a list of
469 // availabe weeks of the month.
472 String monthFormat = (GetNumericDateFormat()[0] == 'y') ? "yyyy/M" : "M/yyyy";
473 String displayText = String.Format(CultureInfo.CurrentCulture, "{0} ({1}):",
474 SR.GetString(SR.CalendarAdapterOptionChooseWeek),
475 Control.VisibleDate.ToString(monthFormat, CultureInfo.CurrentCulture));
476 writer.RenderText(displayText, !addBreakBeforeListControl);
478 // List weeks of days of the selected month. May include
479 // days from the previous and the next month to fill out
480 // all six week choices. This is consistent with the
481 // ASP.NET Calendar control.
483 // Note that the event handling code of this list control
484 // should be implemented according to the index content
487 tempDate = FirstCalendarDay(Control.VisibleDate);
489 arr = new ArrayList();
491 for (int i = 0; i < 6; i++)
493 weekDisplay = tempDate.ToString(abbreviatedMonthDayPattern, CultureInfo.CurrentCulture);
494 weekDisplay += DaySeparator;
495 tempDate = _threadCalendar.AddDays(tempDate, 6);
496 weekDisplay += tempDate.ToString(abbreviatedMonthDayPattern, CultureInfo.CurrentCulture);
497 arr.Add(weekDisplay);
498 tempDate = _threadCalendar.AddDays(tempDate, 1);
500 DataBindAndRender(writer, _weekList, arr);
504 // Based on the month and week selected in case ChooseMonth and ChooseWeek above,
505 // render a list of the dates in the week.
508 String displayText = String.Format(CultureInfo.CurrentCulture, "{0}:", SR.GetString(SR.CalendarAdapterOptionChooseDate));
509 writer.RenderText(displayText, !addBreakBeforeListControl);
511 tempDate = Control.VisibleDate;
513 arr = new ArrayList();
516 StringBuilder dayDisplay = new StringBuilder();
517 bool dayNameFirst = (GetNumericDateFormat()[0] != 'y');
519 for (int i = 0; i < 7; i++)
521 date = tempDate.ToString(abbreviatedMonthDayPattern, CultureInfo.CurrentCulture);
523 if (Control.ShowDayHeader)
525 // Use the short format for displaying day name
526 dayName = GetAbbreviatedDayName(tempDate);
527 dayDisplay.Length = 0;
531 dayDisplay.Append(dayName);
532 dayDisplay.Append(Space);
533 dayDisplay.Append(date);
537 dayDisplay.Append(date);
538 dayDisplay.Append(Space);
539 dayDisplay.Append(dayName);
541 arr.Add(dayDisplay.ToString());
547 tempDate = _threadCalendar.AddDays(tempDate, 1);
549 DataBindAndRender(writer, _dayList, arr);
554 Debug.Assert(false, "Unexpected Secondary UI Mode");
557 writer.ExitStyle(Style);
560 /// <include file='doc\WmlCalendarAdapter.uex' path='docs/doc[@for="WmlCalendarAdapter.HandlePostBackEvent"]/*' />
561 public override bool HandlePostBackEvent(String eventArgument)
563 // This is mainly to capture the option picked by the user on
564 // secondary pages and manipulate SecondaryUIMode accordingly so
565 // Render() can generate the appropriate UI.
566 // It also capture the state "Done" which can be set when a date,
567 // a week or a month is selected or entered in some secondary
570 SecondaryUIMode = Int32.Parse(eventArgument, CultureInfo.InvariantCulture);
572 Debug.Assert(NotSecondaryUI == NotSecondaryUIInit);
573 switch (SecondaryUIMode)
575 case DefaultDateDone:
576 SelectRange(Control.VisibleDate, Control.VisibleDate);
582 String dateText = _textBox.Text;
583 String dateFormat = GetNumericDateFormat();
584 DateTimeFormatInfo currentInfo = DateTimeFormatInfo.CurrentInfo;
585 int eraIndex = _selectList.SelectedIndex;
588 eraIndex < currentInfo.Calendar.Eras.Length)
590 dateText += currentInfo.GetEraName(currentInfo.Calendar.Eras[eraIndex]);
594 DateTime dateTime = DateTime.ParseExact(dateText, dateFormat, null);
595 SelectRange(dateTime, dateTime);
596 Control.VisibleDate = dateTime;
600 _textBoxErrorMessage = SR.GetString(SR.CalendarAdapterTextBoxErrorMessage);
601 SecondaryUIMode = TypeDate;
607 // Set the secondary exit code and raise the selection event for
608 // web page developer to manipulate the selected date.
609 ExitSecondaryUIMode();
610 _chooseOption = FirstPrompt;
616 _chooseOption = SecondaryUIMode; // save in the ViewState
618 // In all 3 cases, continue to the UI that chooses a month
619 SecondaryUIMode = ChooseMonth;
626 /////////////////////////////////////////////////////////////////////
627 // Misc. helper and wrapper functions
628 /////////////////////////////////////////////////////////////////////
630 private int MonthsToDisplay(int screenCharactersHeight)
632 const int MinMonthsToDisplay = 4;
633 const int MaxMonthsToDisplay = 12;
635 if (screenCharactersHeight < MinMonthsToDisplay)
637 return MinMonthsToDisplay;
639 else if (screenCharactersHeight > MaxMonthsToDisplay)
641 return MaxMonthsToDisplay;
643 return screenCharactersHeight;
646 // A helper function to initialize and add a child list control
647 private void InitList(List list,
648 ListCommandEventHandler eventHandler)
650 list.Visible = false;
651 list.ItemCommand += eventHandler;
652 list.EnableViewState = false;
653 Control.Controls.Add(list);
656 private void DataBindListWithEmptyValues(List list, int arraySize)
658 ArrayList arr = new ArrayList();
659 for (int i = 0; i < arraySize; i++)
663 list.DataSource = arr;
667 // A helper function to do the common code for DataBind and
669 private void DataBindAndRender(WmlMobileTextWriter writer,
673 list.DataSource = arr;
676 list.RenderControl(writer);
679 // Abbreviate the Month format from "MMMM" (full
680 // month name) to "MMM" (three-character month abbreviation)
681 private String AbbreviateMonthPattern(String pattern)
683 const String FullMonthFormat = "MMMM";
685 int i = pattern.IndexOf(FullMonthFormat, StringComparison.Ordinal);
688 pattern = pattern.Remove(i, 1);
693 private String GetAbbreviatedDayName(DateTime dateTime)
695 return DateTimeFormatInfo.CurrentInfo.GetAbbreviatedDayName(
696 _threadCalendar.GetDayOfWeek(dateTime));
699 private String GetEra(DateTime dateTime)
701 // We shouldn't need to display the era for the common Gregorian
703 if (DateTimeFormatInfo.CurrentInfo.Calendar.GetType() ==
704 typeof(GregorianCalendar))
710 return dateTime.ToString("gg", CultureInfo.CurrentCulture);
714 private static readonly char[] formatChars =
715 new char[] { 'M', 'd', 'y' };
717 private String GetNumericDateFormat()
719 String shortDatePattern =
720 DateTimeFormatInfo.CurrentInfo.ShortDatePattern;
722 // Guess on what short date pattern should be used
723 int i = shortDatePattern.IndexOfAny(formatChars);
725 char firstFormatChar;
728 firstFormatChar = 'M';
732 firstFormatChar = shortDatePattern[i];
735 // We either use two or four digits for the year
737 if (shortDatePattern.IndexOf("yyyy", StringComparison.Ordinal) == -1)
743 yearPattern = "yyyy";
746 switch (firstFormatChar)
750 return "MMdd" + yearPattern;
752 return "ddMM" + yearPattern;
754 return yearPattern + "MMdd";
758 /////////////////////////////////////////////////////////////////////
760 /////////////////////////////////////////////////////////////////////
762 // Return the first date of the input year and month
763 private DateTime EffectiveVisibleDate(DateTime visibleDate)
765 return _threadCalendar.AddDays(
767 -(_threadCalendar.GetDayOfMonth(visibleDate) - 1));
770 // Return the beginning date of a calendar that includes the
771 // targeting month. The date can actually be in the previous month.
772 private DateTime FirstCalendarDay(DateTime visibleDate)
774 DateTime firstDayOfMonth = EffectiveVisibleDate(visibleDate);
775 int daysFromLastMonth =
776 ((int)_threadCalendar.GetDayOfWeek(firstDayOfMonth)) -
777 NumericFirstDayOfWeek();
779 // Always display at least one day from the previous month
780 if (daysFromLastMonth <= 0)
782 daysFromLastMonth += 7;
784 return _threadCalendar.AddDays(firstDayOfMonth, -daysFromLastMonth);
787 private int NumericFirstDayOfWeek()
789 // Used globalized value by default
790 return(Control.FirstDayOfWeek == FirstDayOfWeek.Default)
791 ? (int) DateTimeFormatInfo.CurrentInfo.FirstDayOfWeek
792 : (int) Control.FirstDayOfWeek;
795 /////////////////////////////////////////////////////////////////////
796 // The followings are event handlers to capture the selection from
797 // the corresponding list control in an secondary page. The index of
798 // the selection is used to determine which and how the next
799 // secondary page is rendered. Some event handlers below update
800 // Calendar.VisibleDate and set SecondaryUIMode with appropriate
802 ////////////////////////////////////////////////////////////////////////
804 private static readonly int[] Options =
805 {DefaultDateDone, TypeDate, DateOption, WeekOption, MonthOption};
807 private void OptionListEventHandler(Object source, ListCommandEventArgs e)
809 SecondaryUIMode = Options[e.ListItem.Index];
810 HandlePostBackEvent(SecondaryUIMode.ToString(CultureInfo.InvariantCulture));
813 private void MonthListEventHandler(Object source, ListCommandEventArgs e)
815 _threadCalendar = DateTimeFormatInfo.CurrentInfo.Calendar;
817 if (e.ListItem.Index == _monthsToDisplay)
820 Control.VisibleDate = _threadCalendar.AddMonths(
821 Control.VisibleDate, _monthsToDisplay);
822 SecondaryUIMode = ChooseMonth;
824 else if (e.ListItem.Index == _monthsToDisplay + 1)
827 Control.VisibleDate = _threadCalendar.AddMonths(
828 Control.VisibleDate, -_monthsToDisplay);
829 SecondaryUIMode = ChooseMonth;
833 // A month was selected
834 Control.VisibleDate = _threadCalendar.AddMonths(
838 if (_chooseOption == MonthOption)
840 // Add the whole month to the date list
841 DateTime beginDate = EffectiveVisibleDate(Control.VisibleDate);
842 Control.VisibleDate = beginDate;
844 DateTime endDate = _threadCalendar.AddMonths(beginDate, 1);
845 endDate = _threadCalendar.AddDays(endDate, -1);
847 SelectRange(beginDate, endDate);
848 HandlePostBackEvent(Done.ToString(CultureInfo.InvariantCulture));
852 SecondaryUIMode = ChooseWeek;
857 private void WeekListEventHandler(Object source, ListCommandEventArgs e)
859 // Get the first calendar day and adjust it to the week the user
860 // selected (to be consistent with the index setting in Render())
861 _threadCalendar = DateTimeFormatInfo.CurrentInfo.Calendar;
863 DateTime tempDate = FirstCalendarDay(Control.VisibleDate);
865 Control.VisibleDate = _threadCalendar.AddDays(tempDate, e.ListItem.Index * 7);
867 if (_chooseOption == WeekOption)
869 // Add the whole week to the date list
870 DateTime endDate = _threadCalendar.AddDays(Control.VisibleDate, 6);
872 SelectRange(Control.VisibleDate, endDate);
873 HandlePostBackEvent(Done.ToString(CultureInfo.InvariantCulture));
877 SecondaryUIMode = ChooseDay;
881 private void DayListEventHandler(Object source, ListCommandEventArgs e)
883 _threadCalendar = DateTimeFormatInfo.CurrentInfo.Calendar;
885 // VisibleDate should have been set with the first day of the week
886 // so the selected index can be used to adjust to the selected day.
887 Control.VisibleDate = _threadCalendar.AddDays(Control.VisibleDate, e.ListItem.Index);
889 SelectRange(Control.VisibleDate, Control.VisibleDate);
890 HandlePostBackEvent(Done.ToString(CultureInfo.InvariantCulture));
893 private void SelectRange(DateTime dateFrom, DateTime dateTo)
895 Debug.Assert(dateFrom <= dateTo, "Bad Date Range");
897 // see if this range differs in any way from the current range
898 // these checks will determine this because the colleciton is sorted
899 TimeSpan ts = dateTo - dateFrom;
900 SelectedDatesCollection selectedDates = Control.SelectedDates;
901 if (selectedDates.Count != ts.Days + 1
902 || selectedDates[0] != dateFrom
903 || selectedDates[selectedDates.Count - 1] != dateTo)
905 selectedDates.SelectRange(dateFrom, dateTo);
906 Control.RaiseSelectionChangedEvent();
910 private bool IsViewStateEnabled()
912 Control ctl = Control;
915 if (!ctl.EnableViewState)