Calendar.cs :  » 2.6.4-mono-.net-core » System.Windows » System » Windows » Controls » C# / CSharp Open Source

Home
C# / CSharp Open Source
1.2.6.4 mono .net core
2.2.6.4 mono core
3.Aspect Oriented Frameworks
4.Bloggers
5.Build Systems
6.Business Application
7.Charting Reporting Tools
8.Chat Servers
9.Code Coverage Tools
10.Content Management Systems CMS
11.CRM ERP
12.Database
13.Development
14.Email
15.Forum
16.Game
17.GIS
18.GUI
19.IDEs
20.Installers Generators
21.Inversion of Control Dependency Injection
22.Issue Tracking
23.Logging Tools
24.Message
25.Mobile
26.Network Clients
27.Network Servers
28.Office
29.PDF
30.Persistence Frameworks
31.Portals
32.Profilers
33.Project Management
34.RSS RDF
35.Rule Engines
36.Script
37.Search Engines
38.Sound Audio
39.Source Control
40.SQL Clients
41.Template Engines
42.Testing
43.UML
44.Web Frameworks
45.Web Service
46.Web Testing
47.Wiki Engines
48.Windows Presentation Foundation
49.Workflows
50.XML Parsers
C# / C Sharp
C# / C Sharp by API
C# / CSharp Tutorial
C# / CSharp Open Source » 2.6.4 mono .net core » System.Windows 
System.Windows » System » Windows » Controls » Calendar.cs
// (c) Copyright Microsoft Corporation.
// This source is subject to the Microsoft Public License (Ms-PL).
// Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
// All other rights reserved.

using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Windows.Automation.Peers;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Media;

namespace System.Windows.Controls{
    /// <summary>
    /// Represents a control that enables a user to select a date by using a visual calendar display. 
    /// </summary>
    [TemplatePart(Name = Calendar.ElementRoot, Type = typeof(Panel))]
    [TemplatePart(Name = Calendar.ElementMonth, Type = typeof(CalendarItem))]
    public partial class Calendar : Control
    {
        #region Constants

        private const string ElementRoot = "Root";
        private const string ElementMonth = "CalendarItem";

        private const int COLS = 7;
        private const int ROWS = 7;
        private const int YEAR_ROWS = 3;
        private const int YEAR_COLS = 4;

        #endregion Constants

        #region Data
        internal CalendarDayButton _focusButton;
        internal bool _hasFocus;
        internal DateTime? _hoverEnd;
        internal int? _hoverEndIndex;
        internal DateTime? _hoverStart;
        internal int? _hoverStartIndex;
        private bool _isShiftPressed;
        internal DateTime? _lastSelectedDate;
        internal Panel _root;
        internal bool _isMouseSelection;
        internal Collection<DateTime> _removedItems;
        private DateTime _selectedMonth;
        private DateTime _selectedYear;


        #endregion Data

        #region Public Events
        /// <summary>
        /// Occurs when a date is selected.
        /// </summary>
        public event EventHandler<SelectionChangedEventArgs> SelectedDatesChanged;

        /// <summary>
        /// Occurs when the DisplayDate property is changed.
        /// </summary>
        public event EventHandler<CalendarDateChangedEventArgs> DisplayDateChanged;

        /// <summary>
        /// Occurs when the DisplayMode property is changed. 
        /// </summary>
        public event EventHandler<CalendarModeChangedEventArgs> DisplayModeChanged;

        #endregion Public Events

        /// <summary>
        /// Initializes a new instance of the Calendar class.
        /// </summary>
        public Calendar()
        {
            this.DisplayDate = DateTime.Today;
            this.GotFocus += new RoutedEventHandler(Calendar_GotFocus);
            this.LostFocus += new RoutedEventHandler(Calendar_LostFocus);
            this.IsEnabledChanged += new DependencyPropertyChangedEventHandler(OnIsEnabledChanged);
            this.FirstDayOfWeek = DateTimeHelper.GetCurrentDateFormat().FirstDayOfWeek;
            this.IsTodayHighlighted = true;
            this.MouseLeftButtonUp += new MouseButtonEventHandler(Calendar_MouseLeftButtonUp);
            this.BlackoutDates = new CalendarBlackoutDatesCollection(this);
            this.SelectedDates = new SelectedDatesCollection(this);
            this._removedItems = new Collection<DateTime>();
            DefaultStyleKey = typeof(Calendar);
        }

        #region Public Properties

        #region BlackoutDates

        /// <summary>
        /// Gets or sets the dates that are not selectable.
        /// </summary>
        public CalendarBlackoutDatesCollection BlackoutDates
        {
            get;
            private set;
        }

        #endregion BlackoutDates

        #region CalendarButtonStyle

        /// <summary>
        /// Gets or sets the style for displaying a CalendarButton.
        /// </summary>
        public Style CalendarButtonStyle
        {
            get { return (Style)GetValue(CalendarButtonStyleProperty); }
            set { SetValue(CalendarButtonStyleProperty, value); }
        }

        /// <summary>
        /// Identifies the CalendarButtonStyle dependency property.
        /// </summary>
        public static readonly DependencyProperty CalendarButtonStyleProperty =
            DependencyProperty.Register(
            "CalendarButtonStyle",
            typeof(Style),
            typeof(Calendar),
            new PropertyMetadata(OnCalendarButtonStyleChanged));

        private static void OnCalendarButtonStyleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            Style newStyle = e.NewValue as Style;
            Style oldStyle = e.OldValue as Style;
            Calendar c = d as Calendar;

            if (newStyle != null && c != null)
            {
                CalendarItem monthControl = c.MonthControl;

                if (monthControl != null && monthControl.YearView != null)
                {
                    foreach (UIElement child in monthControl.YearView.Children)
                    {
                        CalendarButton calendarButton = child as CalendarButton;

                        if (calendarButton != null)
                        {
                            EnsureCalendarButtonStyle(calendarButton, oldStyle, newStyle);
                        }
                    }
                }
            }
        }

        #endregion CalendarButtonStyle

        #region CalendarDayButtonStyle

        /// <summary>
        /// Gets or sets the style for displaying a day.
        /// </summary>
        public Style CalendarDayButtonStyle
        {
            get { return (Style)GetValue(CalendarDayButtonStyleProperty); }
            set { SetValue(CalendarDayButtonStyleProperty, value); }
        }


        /// <summary>
        /// Identifies the DayButtonStyle dependency property.
        /// </summary>
        public static readonly DependencyProperty CalendarDayButtonStyleProperty =
            DependencyProperty.Register(
            "CalendarDayButtonStyle",
            typeof(Style),
            typeof(Calendar),
            new PropertyMetadata(OnCalendarDayButtonStyleChanged));

        private static void OnCalendarDayButtonStyleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            Style newStyle = e.NewValue as Style;
            Style oldStyle = e.OldValue as Style;
            Calendar c = d as Calendar;

            if (newStyle != null && c != null)
            {
                CalendarItem monthControl = c.MonthControl;

                if (monthControl != null && monthControl.MonthView != null)
                {
                    foreach (UIElement child in monthControl.MonthView.Children)
                    {
                        CalendarDayButton dayButton = child as CalendarDayButton;

                        if (dayButton != null)
                        {
                            EnsureDayButtonStyle(dayButton, oldStyle, newStyle);
                        }
                    }
                }
            }
        }

        #endregion CalendarDayButtonStyle

        #region CalendarItemStyle

        /// <summary>
        /// Gets or sets the style for a Month.
        /// </summary>
        public Style CalendarItemStyle
        {
            get { return (Style)GetValue(CalendarItemStyleProperty); }
            set { SetValue(CalendarItemStyleProperty, value); }
        }

        /// <summary>
        /// Identifies the MonthStyle dependency property.
        /// </summary>
        public static readonly DependencyProperty CalendarItemStyleProperty =
            DependencyProperty.Register(
            "CalendarItemStyle",
            typeof(Style),
            typeof(Calendar),
            new PropertyMetadata(OnCalendarItemStyleChanged));

        private static void OnCalendarItemStyleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            Style newStyle = e.NewValue as Style;
            Style oldStyle = e.OldValue as Style;
            Calendar c = d as Calendar;

            if (newStyle != null && c != null)
            {
                CalendarItem monthControl = c.MonthControl;

                if (monthControl != null)
                {
                    EnsureMonthStyle(monthControl, oldStyle, newStyle);
                }
            }
        }

        #endregion CalendarItemStyle

        #region DisplayDate

        /// <summary>
        /// Gets or sets the date to display.
        /// </summary>
        /// 
        [TypeConverter(typeof(DateTimeTypeConverter))]
        public DateTime DisplayDate
        {
            get { return (DateTime)GetValue(DisplayDateProperty); }
            set { SetValue(DisplayDateProperty, value); }
        }

        /// <summary>
        /// Identifies the DisplayDate dependency property.
        /// </summary>
        public static readonly DependencyProperty DisplayDateProperty =
            DependencyProperty.Register(
            "DisplayDate",
            typeof(DateTime),
            typeof(Calendar),
            new PropertyMetadata(OnDisplayDateChanged));

        /// <summary>
        /// DisplayDateProperty property changed handler.
        /// </summary>
        /// <param name="d">Calendar that changed its DisplayDate.</param>
        /// <param name="e">DependencyPropertyChangedEventArgs.</param>
        private static void OnDisplayDateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            Calendar c = d as Calendar;
            Debug.Assert(c != null);
            DateTime removedDate, addedDate;

            addedDate = (DateTime)e.NewValue;
            removedDate = (DateTime)e.OldValue;

            //If DisplayDate < DisplayDateStart, DisplayDate = DisplayDateStart
            if (DateTime.Compare(addedDate, c.DisplayDateRangeStart) < 0)
            {
                c.DisplayDate = c.DisplayDateRangeStart;
                return;
            }

            //If DisplayDate > DisplayDateEnd, DisplayDate = DisplayDateEnd
            if (DateTime.Compare(addedDate, c.DisplayDateRangeEnd) > 0)
            {
                c.DisplayDate = c.DisplayDateRangeEnd;
                return;
            }

            c.DisplayDateInternal = DateTimeHelper.DiscardDayTime(addedDate);
            c.UpdateMonths();
            c.OnDisplayDate(new CalendarDateChangedEventArgs(removedDate, addedDate));
        }

        #endregion DisplayDate

        #region DisplayDateEnd

        /// <summary>
        /// Gets or sets the last date to be displayed.
        /// </summary>
        /// 
        [TypeConverter(typeof(DateTimeTypeConverter))]
        public DateTime? DisplayDateEnd
        {
            get { return (DateTime?)GetValue(DisplayDateEndProperty); }
            set { SetValue(DisplayDateEndProperty, value); }
        }

        /// <summary>
        /// Identifies the DisplayDateEnd dependency property.
        /// </summary>
        public static readonly DependencyProperty DisplayDateEndProperty =
            DependencyProperty.Register(
            "DisplayDateEnd",
            typeof(DateTime?),
            typeof(Calendar),
            new PropertyMetadata(OnDisplayDateEndChanged));

        /// <summary>
        /// DisplayDateEndProperty property changed handler.
        /// </summary>
        /// <param name="d">Calendar that changed its DisplayDateEnd.</param>
        /// <param name="e">DependencyPropertyChangedEventArgs.</param>
        private static void OnDisplayDateEndChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            Calendar c = d as Calendar;
            Debug.Assert(c != null);

            if (!c.IsHandlerSuspended(Calendar.DisplayDateEndProperty))
            {
                DateTime? newValue = e.NewValue as DateTime?;

                if (newValue.HasValue)
                {
                    //DisplayDateEnd coerces to the value of the SelectedDateMax if SelectedDateMax > DisplayDateEnd
                    DateTime? selectedDateMax = SelectedDateMax(c);

                    if (selectedDateMax.HasValue && DateTime.Compare(selectedDateMax.Value, newValue.Value) > 0)
                    {
                        c.DisplayDateEnd = selectedDateMax.Value;
                        return;
                    }

                    // if DisplayDateEnd < DisplayDateStart, DisplayDateEnd = DisplayDateStart
                    if (DateTime.Compare(newValue.Value, c.DisplayDateRangeStart) < 0)
                    {
                        c.DisplayDateEnd = c.DisplayDateStart;
                        return;
                    }

                    //If DisplayDate > DisplayDateEnd, DisplayDate = DisplayDateEnd
                    if (DateTimeHelper.CompareYearMonth(newValue.Value, c.DisplayDateInternal) < 0)
                    {
                        c.DisplayDate = newValue.Value;
                    }
                }
                c.UpdateMonths();
            }
        }

        #endregion DisplayDateEnd

        #region DisplayDateStart

        /// <summary>
        /// Gets or sets the first date to be displayed.
        /// </summary>
        /// 
        [TypeConverter(typeof(DateTimeTypeConverter))]
        public DateTime? DisplayDateStart
        {
            get { return (DateTime?)GetValue(DisplayDateStartProperty); }
            set { SetValue(DisplayDateStartProperty, value); }
        }

        /// <summary>
        /// Identifies the DisplayDateStart dependency property.
        /// </summary>
        public static readonly DependencyProperty DisplayDateStartProperty =
            DependencyProperty.Register(
            "DisplayDateStart",
            typeof(DateTime?),
            typeof(Calendar),
            new PropertyMetadata(OnDisplayDateStartChanged));

        /// <summary>
        /// DisplayDateStartProperty property changed handler.
        /// </summary>
        /// <param name="d">Calendar that changed its DisplayDateStart.</param>
        /// <param name="e">DependencyPropertyChangedEventArgs.</param>
        private static void OnDisplayDateStartChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            Calendar c = d as Calendar;
            Debug.Assert(c != null);

            if (!c.IsHandlerSuspended(Calendar.DisplayDateStartProperty))
            {
                DateTime? newValue = e.NewValue as DateTime?;

                if (newValue.HasValue)
                {
                    //DisplayDateStart coerces to the value of the SelectedDateMin if SelectedDateMin < DisplayDateStart
                    DateTime? selectedDateMin = SelectedDateMin(c);

                    if (selectedDateMin.HasValue && DateTime.Compare(selectedDateMin.Value, newValue.Value) < 0)
                    {
                        c.DisplayDateStart = selectedDateMin.Value;
                        return;
                    }

                    // if DisplayDateStart > DisplayDateEnd, DisplayDateEnd = DisplayDateStart
                    if (DateTime.Compare(newValue.Value, c.DisplayDateRangeEnd) > 0)
                    {
                        c.DisplayDateEnd = c.DisplayDateStart;
                    }

                    //If DisplayDate < DisplayDateStart, DisplayDate = DisplayDateStart
                    if (DateTimeHelper.CompareYearMonth(newValue.Value, c.DisplayDateInternal) > 0)
                    {
                        c.DisplayDate = newValue.Value;
                    }
                }
                c.UpdateMonths();
            }
        }

        #endregion DisplayDateStart

        #region DisplayMode

        /// <summary>
        /// Gets or sets a value indicating whether the calendar is displayed in months or years.
        /// </summary>
        public CalendarMode DisplayMode
        {
            get { return (CalendarMode)GetValue(DisplayModeProperty); }
            set { SetValue(DisplayModeProperty, value); }
        }

        /// <summary>
        /// Identifies the DisplayMode dependency property.
        /// </summary>
        public static readonly DependencyProperty DisplayModeProperty =
            DependencyProperty.Register(
            "DisplayMode",
            typeof(CalendarMode),
            typeof(Calendar),
            new PropertyMetadata(OnDisplayModePropertyChanged));

        /// <summary>
        /// DisplayModeProperty property changed handler.
        /// </summary>
        /// <param name="d">Calendar that changed its DisplayMode.</param>
        /// <param name="e">DependencyPropertyChangedEventArgs.</param>
        private static void OnDisplayModePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            Calendar c = d as Calendar;
            Debug.Assert(c != null);
            CalendarMode mode = (CalendarMode)e.NewValue;
            CalendarMode oldMode = (CalendarMode)e.OldValue;
            CalendarItem monthControl = c.MonthControl;

            if (IsValidDisplayMode(mode))
            {
                if (monthControl != null)
                {
                    switch (oldMode)
                    {
                        case CalendarMode.Month:
                            {
                                c.SelectedYear = c.DisplayDateInternal;
                                c.SelectedMonth = c.DisplayDateInternal;
                                break;
                            }
                        case CalendarMode.Year:
                            {
                                c.DisplayDate = c.SelectedMonth;
                                c.SelectedYear = c.SelectedMonth;
                                break;
                            }
                        case CalendarMode.Decade:
                            {
                                c.DisplayDate = c.SelectedYear;
                                c.SelectedMonth = c.SelectedYear;
                                break;
                            }
                    }
                    
                    switch (mode)
                    {
                        case CalendarMode.Month:
                            {
                                c.OnMonthClick();
                                break;
                            }
                        case CalendarMode.Year:
                        case CalendarMode.Decade:
                            {
                                c.OnHeaderClick();
                                break;
                            }
                    }
                }
                c.OnDisplayModeChanged(new CalendarModeChangedEventArgs((CalendarMode)e.OldValue, mode));
            }
            else
            {
                throw new ArgumentOutOfRangeException("d", Resource.Calendar_OnDisplayModePropertyChanged_InvalidValue);
            }
        }

        #endregion DisplayMode

        #region FirstDayOfWeek

        /// <summary>
        /// Gets or sets the day that is considered the beginning of the week.
        /// </summary>
        public DayOfWeek FirstDayOfWeek
        {
            get { return (DayOfWeek)GetValue(FirstDayOfWeekProperty); }
            set { SetValue(FirstDayOfWeekProperty, value); }
        }

        /// <summary>
        /// Identifies the FirstDayOfWeek dependency property.
        /// </summary>
        public static readonly DependencyProperty FirstDayOfWeekProperty =
            DependencyProperty.Register(
            "FirstDayOfWeek",
            typeof(DayOfWeek),
            typeof(Calendar),
            new PropertyMetadata(OnFirstDayOfWeekChanged));

        /// <summary>
        /// FirstDayOfWeekProperty property changed handler.
        /// </summary>
        /// <param name="d">Calendar that changed its FirstDayOfWeek.</param>
        /// <param name="e">DependencyPropertyChangedEventArgs.</param>
        private static void OnFirstDayOfWeekChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            Calendar c = d as Calendar;
            Debug.Assert(c != null);

            if (IsValidFirstDayOfWeek(e.NewValue))
            {
                c.UpdateMonths();
            }
            else
            {
                throw new ArgumentOutOfRangeException("d", Resource.Calendar_OnFirstDayOfWeekChanged_InvalidValue);
            }
        }

        #endregion FirstDayOfWeek

        #region IsEnabled

        /// <summary>
        ///  Called when the IsEnabled property changes.
        /// </summary>
        /// <param name="sender">Sender object</param>
        /// <param name="e">Property changed args</param>
        private void OnIsEnabledChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            Debug.Assert(e.NewValue is bool);
            bool isEnabled = (bool)e.NewValue;

            if (MonthControl != null)
            {
                MonthControl.UpdateDisabledGrid(isEnabled);
            }
        }

        #endregion IsEnabled

        #region IsTodayHighlighted

        /// <summary>
        /// Gets or sets a value indicating whether the current date is highlighted.
        /// </summary>
        public bool IsTodayHighlighted
        {
            get { return (bool)GetValue(IsTodayHighlightedProperty); }
            set { SetValue(IsTodayHighlightedProperty, value); }
        }

        /// <summary>
        /// Identifies the IsTodayHighlighted dependency property.
        /// </summary>
        public static readonly DependencyProperty IsTodayHighlightedProperty =
            DependencyProperty.Register(
            "IsTodayHighlighted",
            typeof(bool),
            typeof(Calendar),
            new PropertyMetadata(OnIsTodayHighlightedChanged));

        /// <summary>
        /// IsTodayHighlightedProperty property changed handler.
        /// </summary>
        /// <param name="d">Calendar that changed its IsTodayHighlighted.</param>
        /// <param name="e">DependencyPropertyChangedEventArgs.</param>
        private static void OnIsTodayHighlightedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            Calendar c = d as Calendar;
            Debug.Assert(c != null);

            if (c.DisplayDate != null)
            {
                int i = DateTimeHelper.CompareYearMonth(c.DisplayDateInternal, DateTime.Today);

                if (i > -2 && i < 2)
                {
                    c.UpdateMonths();
                }
            }
        }

        #endregion IsTodayHighlighted

        #region SelectedDate

        /// <summary>
        /// Gets or sets the currently selected date.
        /// </summary>
        /// 
        [TypeConverter(typeof(DateTimeTypeConverter))]
        public DateTime? SelectedDate
        {
            get { return (DateTime?)GetValue(SelectedDateProperty); }
            set { SetValue(SelectedDateProperty, value); }
        }

        /// <summary>
        /// Identifies the SelectedDate dependency property.
        /// </summary>
        public static readonly DependencyProperty SelectedDateProperty =
            DependencyProperty.Register(
            "SelectedDate",
            typeof(DateTime?),
            typeof(Calendar),
            new PropertyMetadata(OnSelectedDateChanged));

        /// <summary>
        /// SelectedDateProperty property changed handler.
        /// </summary>
        /// <param name="d">Calendar that changed its SelectedDate.</param>
        /// <param name="e">DependencyPropertyChangedEventArgs.</param>
        private static void OnSelectedDateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            Calendar c = d as Calendar;
            Debug.Assert(c != null);

            if (!c.IsHandlerSuspended(Calendar.SelectedDateProperty))
            {
                if (c.SelectionMode != CalendarSelectionMode.None)
                {
                    DateTime? addedDate;

                    addedDate = (DateTime?)e.NewValue;

                    if (IsValidDateSelection(c, addedDate))
                    {
                        if (addedDate == null)
                        {
                            c.SelectedDates.Clear();
                        }
                        else
                        {
                            if (addedDate.HasValue && !(c.SelectedDates.Count > 0 && c.SelectedDates[0] == addedDate.Value))
                            {
                                foreach (DateTime item in c.SelectedDates)
                                {
                                    c._removedItems.Add(item);
                                }
                                c.SelectedDates.ClearInternal();
                                //the value is added as a range so that the SelectedDatesChanged event can be thrown with all the removed items
                                c.SelectedDates.AddRange(addedDate.Value, addedDate.Value);
                            }
                        }

                        //We update the LastSelectedDate for only the Single mode.For the other modes it automatically gets updated
                        //when the HoverEnd is updated.
                        if (c.SelectionMode == CalendarSelectionMode.SingleDate)
                        {
                            c.LastSelectedDate = addedDate;
                        }
                    }
                    else
                    {
                        throw new ArgumentOutOfRangeException("d", Resource.Calendar_OnSelectedDateChanged_InvalidValue);
                    }
                }
                else
                {
                    throw new InvalidOperationException(Resource.Calendar_OnSelectedDateChanged_InvalidOperation);
                }
            }
        }

        #endregion SelectedDate

        #region SelectedDates

        /// <summary>
        /// Gets the dates that are currently selected.
        /// </summary>
        public SelectedDatesCollection SelectedDates
        {
            get;
            private set;
        }

        #endregion SelectedDates

        #region SelectionMode

        /// <summary>
        /// Gets or sets the selection mode for the calendar.
        /// </summary>
        public CalendarSelectionMode SelectionMode
        {
            get { return (CalendarSelectionMode)GetValue(SelectionModeProperty); }
            set { SetValue(SelectionModeProperty, value); }
        }

        /// <summary>
        /// Identifies the SelectionMode dependency property.
        /// </summary>
        public static readonly DependencyProperty SelectionModeProperty =
            DependencyProperty.Register(
            "SelectionMode",
            typeof(CalendarSelectionMode),
            typeof(Calendar),
            new PropertyMetadata(OnSelectionModeChanged));

        private static void OnSelectionModeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            Calendar c = d as Calendar;
            Debug.Assert(c != null);

            if (IsValidSelectionMode(e.NewValue))
            {
                c.SetValueNoCallback(Calendar.SelectedDateProperty, null);
                c.SelectedDates.Clear();
            }
            else
            {
                throw new ArgumentOutOfRangeException("d", Resource.Calendar_OnSelectionModeChanged_InvalidValue);
            }
        }

        #endregion SelectionMode

        #endregion Public Properties

        #region Protected Properties
        #endregion Protected Properties

        #region Internal Events

        internal event MouseButtonEventHandler DayButtonMouseUp;

        #endregion Internal Events

        #region Internal Properties

        /// <summary>
        /// This flag is used to determine whether DatePicker should change its 
        /// DisplayDate because of a SelectedDate change on its Calendar
        /// </summary>
        internal bool DatePickerDisplayDateFlag
        {
            get;
            set;
        }

        internal DateTime DisplayDateInternal
        {
            get;
            private set;
        }

        internal DateTime DisplayDateRangeEnd
        {
            get
            {
                return this.DisplayDateEnd.GetValueOrDefault(DateTime.MaxValue);
            }
        }

        internal DateTime DisplayDateRangeStart
        {
            get
            {
                return this.DisplayDateStart.GetValueOrDefault(DateTime.MinValue);
            }
        }

        internal CalendarButton FocusCalendarButton
        {
            get;
            set;
        }

        internal DateTime? HoverEnd
        {
            get { return this._hoverEnd; }
            set
            {
                this._hoverEnd = value;
                this.LastSelectedDate = value;
            }
        }

        internal DateTime? LastSelectedDate
        {
            get { return _lastSelectedDate; }
            set
            {
                _lastSelectedDate = value;

                if (this.SelectionMode == CalendarSelectionMode.None)
                {
                    if (this._focusButton != null)
                    {
                        this._focusButton.IsCurrent = false;
                    }
                    this._focusButton = FindDayButtonFromDay(LastSelectedDate.Value);
                    if (this._focusButton != null)
                    {
                        this._focusButton.IsCurrent = this._hasFocus;
                    }
                }

            }
        }

        internal CalendarItem MonthControl
        {
            get
            {
                if (this._root != null && this._root.Children.Count > 0)
                {
                    return this._root.Children[0] as CalendarItem;
                }
                return null;
            }
        }

        internal DateTime SelectedMonth
        {
            get
            {
                return this._selectedMonth;
            }
            set
            {
                int monthDifferenceStart = DateTimeHelper.CompareYearMonth(value, this.DisplayDateRangeStart);
                int monthDifferenceEnd = DateTimeHelper.CompareYearMonth(value, this.DisplayDateRangeEnd);

                if (monthDifferenceStart >= 0 && monthDifferenceEnd <= 0)
                {
                    this._selectedMonth = DateTimeHelper.DiscardDayTime(value);
                }
                else
                {
                    if (monthDifferenceStart < 0)
                    {
                        this._selectedMonth = DateTimeHelper.DiscardDayTime(this.DisplayDateRangeStart);
                    }
                    else
                    {
                        Debug.Assert(monthDifferenceEnd > 0);
                        this._selectedMonth = DateTimeHelper.DiscardDayTime(this.DisplayDateRangeEnd);
                    }
                }

            }
        }

        internal DateTime SelectedYear
        {
            get
            {
                return this._selectedYear;
            }
            set
            {
                if (value.Year < this.DisplayDateRangeStart.Year)
                {
                    this._selectedYear = this.DisplayDateRangeStart;
                }
                else
                {
                    if (value.Year > this.DisplayDateRangeEnd.Year)
                    {
                        this._selectedYear = this.DisplayDateRangeEnd;
                    }
                    else
                    {
                        this._selectedYear = value;
                    }
                }
            }
        }

        #endregion Internal Properties

        #region Private Properties

        #endregion Private Properties

        #region Public Methods

        /// <summary>
        /// Invoked whenever application code or an internal process, 
        /// such as a rebuilding layout pass, calls the ApplyTemplate method.
        /// </summary>
        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            _root = GetTemplateChild(ElementRoot) as Panel;

            this.SelectedMonth = this.DisplayDate;
            this.SelectedYear = this.DisplayDate;


            if (_root != null)
            {
                CalendarItem month = GetTemplateChild(ElementMonth) as CalendarItem;

                if (month != null)
                {
                    month.Owner = this;

                    if (this.CalendarItemStyle != null)
                    {
                        month.Style = this.CalendarItemStyle;
                    }
                    // 
                }
            }


            this.SizeChanged += new SizeChangedEventHandler(Calendar_SizeChanged);
            this.KeyDown += new KeyEventHandler(Calendar_KeyDown);
            this.KeyUp += new KeyEventHandler(Calendar_KeyUp);
        }

        /// <summary>
        /// Provides a text representation of the selected date.
        /// </summary>
        /// <returns>A text representation of the selected date, or an empty string if SelectedDate is a null reference.</returns>
        public override string ToString()
        {
            if (this.SelectedDate != null)
            {
                return this.SelectedDate.Value.ToString(DateTimeHelper.GetCurrentDateFormat());
            }
            else
            {
                return string.Empty;
            }
        }

        #endregion Public Methods

        #region Protected Methods

        /// <summary>
        /// Creates the automation peer for this Calendar Control.
        /// </summary>
        /// <returns></returns>
        protected override AutomationPeer OnCreateAutomationPeer()
        {
            return new CalendarAutomationPeer(this);
        }

        #endregion Protected Methods

        #region Internal Methods

        internal CalendarDayButton FindDayButtonFromDay(DateTime day)
        {
            CalendarDayButton b;
            DateTime? d;
            CalendarItem monthControl = this.MonthControl;

            // 
            int count = ROWS * COLS;
            if (monthControl != null)
            {
                if (monthControl.MonthView != null)
                {
                    for (int childIndex = COLS; childIndex < count; childIndex++)
                    {
                        b = monthControl.MonthView.Children[childIndex] as CalendarDayButton;
                        d = b.DataContext as DateTime?;

                        if (d.HasValue)
                        {
                            if (DateTimeHelper.CompareDays(d.Value, day) == 0)
                            {
                                return b;
                            }
                        }
                    }
                }
            }
            return null;
        }

        //This method highlights the days in MultiSelection mode without adding them
        //to the SelectedDates collection.
        internal void HighlightDays()
        {
            if (this.HoverEnd != null && this._hoverStart != null)
            {
                int startIndex, endIndex, i;
                CalendarDayButton b;
                DateTime? d;
                CalendarItem monthControl = this.MonthControl;

                //This assumes a contiguous set of dates:
                if (this._hoverEndIndex != null && this._hoverStartIndex != null)
                {
                    SortHoverIndexes(out startIndex, out endIndex);

                    for (i = startIndex; i <= endIndex; i++)
                    {
                        b = monthControl.MonthView.Children[i] as CalendarDayButton;
                        b.IsSelected = true;
                        d = b.DataContext as DateTime?;

                        if (d.HasValue && DateTimeHelper.CompareDays(this.HoverEnd.Value, d.Value) == 0)
                        {
                            if (this._focusButton != null)
                            {
                                this._focusButton.IsCurrent = false;
                            }
                            b.IsCurrent = this._hasFocus;
                            this._focusButton = b;
                        }
                    }
                }
            }
        }

        internal static bool IsValidDateSelection(Calendar cal, object value)
        {
            if (value == null)
            {
                return true;
            }
            else
            {
                if (cal.BlackoutDates.Contains((DateTime)value))
                {
                    return false;
                }
                else
                {
                    if (DateTime.Compare((DateTime)value, cal.DisplayDateRangeStart) < 0)
                    {
                        cal.SetValueNoCallback(Calendar.DisplayDateStartProperty, value);
                    }
                    else if (DateTime.Compare((DateTime)value, cal.DisplayDateRangeEnd) > 0)
                    {
                        cal.SetValueNoCallback(Calendar.DisplayDateEndProperty, value);
                    }
                    return true;
                }
            }
        }

        internal void OnDayButtonMouseUp(MouseButtonEventArgs e)
        {
            MouseButtonEventHandler handler = this.DayButtonMouseUp;
            if (null != handler)
            {
                handler(this, e);
            }
        }

        // If the day is a trailing day, Update the DisplayDate
        internal void OnDayClick(DateTime selectedDate)
        {
            Debug.Assert(this.DisplayMode == CalendarMode.Month);
            int i = DateTimeHelper.CompareYearMonth(selectedDate, this.DisplayDateInternal);

            if (this.SelectionMode == CalendarSelectionMode.None)
            {
                this.LastSelectedDate = selectedDate;
            }

            if (i > 0)
            {
                OnNextClick();
            }
            else if (i < 0)
            {
                OnPreviousClick();
            }
        }

        internal void OnNextClick()
        {
            if (this.DisplayMode == CalendarMode.Month && this.DisplayDate != null)
            {
                DateTime? d = DateTimeHelper.AddMonths(DateTimeHelper.DiscardDayTime(this.DisplayDate), 1);
                if (d.HasValue)
                {
                    if (!this.LastSelectedDate.HasValue || DateTimeHelper.CompareYearMonth(this.LastSelectedDate.Value, d.Value) != 0)
                    {
                        this.LastSelectedDate = d.Value;
                    }
                    this.DisplayDate = d.Value;
                }
            }
            else
            {
                if (this.DisplayMode == CalendarMode.Year)
                {
                    DateTime? d = DateTimeHelper.AddYears(new DateTime(this.SelectedMonth.Year,1,1), 1);

                    if (d.HasValue)
                    {
                        this.SelectedMonth = d.Value;
                    }
                    else
                    {
                        this.SelectedMonth = DateTimeHelper.DiscardDayTime(this.DisplayDateRangeEnd);
                    }
                }
                else
                {
                    Debug.Assert(this.DisplayMode == CalendarMode.Decade);

                    DateTime? d = DateTimeHelper.AddYears(new DateTime(this.SelectedYear.Year, 1, 1), 10);

                    if (d.HasValue)
                    {
                        int decade = Math.Max(1, DateTimeHelper.DecadeOfDate(d.Value));
                        this.SelectedYear = new DateTime(decade, 1, 1);
                    }
                    else
                    {
                        this.SelectedYear = DateTimeHelper.DiscardDayTime(this.DisplayDateRangeEnd);
                    }
                }
                UpdateMonths();
            }
        }

        internal void OnPreviousClick()
        {
            if (this.DisplayMode == CalendarMode.Month && this.DisplayDate != null)
            {
                DateTime? d = DateTimeHelper.AddMonths(DateTimeHelper.DiscardDayTime(this.DisplayDate), -1);
                if (d.HasValue)
                {
                    if (!this.LastSelectedDate.HasValue || DateTimeHelper.CompareYearMonth(this.LastSelectedDate.Value, d.Value) != 0)
                    {
                        this.LastSelectedDate = d.Value;
                    }
                    this.DisplayDate = d.Value;
                }
            }
            else
            {
                if (this.DisplayMode == CalendarMode.Year)
                {
                    DateTime? d = DateTimeHelper.AddYears(new DateTime(this.SelectedMonth.Year, 1, 1), -1);

                    if (d.HasValue)
                    {
                        this.SelectedMonth = d.Value;
                    }
                    else
                    {
                        this.SelectedMonth = DateTimeHelper.DiscardDayTime(this.DisplayDateRangeStart);
                    }
                }
                else
                {
                    Debug.Assert(this.DisplayMode == CalendarMode.Decade);

                    DateTime? d = DateTimeHelper.AddYears(new DateTime(this.SelectedYear.Year, 1, 1), -10);

                    if (d.HasValue)
                    {
                        int decade = Math.Max(1, DateTimeHelper.DecadeOfDate(d.Value));
                        this.SelectedYear = new DateTime(decade, 1, 1);
                    }
                    else
                    {
                        this.SelectedYear = DateTimeHelper.DiscardDayTime(this.DisplayDateRangeStart);
                    }
                }
                UpdateMonths();
            }
        }

        internal void OnSelectedDatesCollectionChanged(SelectionChangedEventArgs e)
        {
            if (IsSelectionChanged(e))
            {
                EventHandler<SelectionChangedEventArgs> handler = this.SelectedDatesChanged;

                if (null != handler)
                {
                    handler(this, e);
                }

                if (AutomationPeer.ListenerExists(AutomationEvents.SelectionItemPatternOnElementSelected) ||
                    AutomationPeer.ListenerExists(AutomationEvents.SelectionItemPatternOnElementAddedToSelection) ||
                    AutomationPeer.ListenerExists(AutomationEvents.SelectionItemPatternOnElementRemovedFromSelection))
                {
                    CalendarAutomationPeer peer = FrameworkElementAutomationPeer.FromElement(this) as CalendarAutomationPeer;
                    if (peer != null)
                    {
                        peer.RaiseSelectionEvents(e);
                    }
                }
            }
        }

        internal void ResetStates()
        {
            CalendarDayButton d;
            CalendarItem monthControl = this.MonthControl;
            int count = ROWS * COLS;
            if (monthControl != null)
            {
                if (monthControl.MonthView != null)
                {
                    for (int childIndex = COLS; childIndex < count; childIndex++)
                    {
                        d = monthControl.MonthView.Children[childIndex] as CalendarDayButton;
                        d.IsMouseOverOverride = false;
                    }
                }
            }
        }

        //This method unhighlights the days that were hovered over but not added to the 
        //SelectedDates collection or unhighlights the previously selected days in SingleRange Mode
        internal void UnHighlightDays()
        {
            if (this.HoverEnd != null && this._hoverStart != null)
            {
                CalendarItem monthControl = this.MonthControl;
                CalendarDayButton b;
                DateTime? d;

                if (this._hoverEndIndex != null && this._hoverStartIndex != null)
                {
                    int startIndex, endIndex, i;
                    SortHoverIndexes(out startIndex, out endIndex);

                    if (this.SelectionMode == CalendarSelectionMode.MultipleRange)
                    {
                        for (i = startIndex; i <= endIndex; i++)
                        {
                            b = monthControl.MonthView.Children[i] as CalendarDayButton;
                            d = b.DataContext as DateTime?;

                            if (d.HasValue)
                            {
                                if (!this.SelectedDates.Contains(d.Value))
                                {
                                    b.IsSelected = false;
                                }
                            }
                        }
                    }
                    else
                    {
                        //It is SingleRange
                        for (i = startIndex; i <= endIndex; i++)
                        {
                            (monthControl.MonthView.Children[i] as CalendarDayButton).IsSelected = false;
                        }
                    }
                }
            }
        }

        internal void UpdateMonths()
        {
            CalendarItem monthControl = this.MonthControl;
            if (monthControl != null)
            {
                switch (this.DisplayMode)
                {
                    case CalendarMode.Month:
                        {
                            monthControl.UpdateMonthMode();
                            break;
                        }
                    case CalendarMode.Year:
                        {
                            monthControl.UpdateYearMode();
                            break;
                        }
                    case CalendarMode.Decade:
                        {
                            monthControl.UpdateDecadeMode();
                            break;
                        }
                }
            }
        }

        #endregion Internal Methods

        #region Private Methods

        // This method adds the days that were selected by Keyboard to the SelectedDays Collection 
        private void AddSelection()
        {
            if (this.HoverEnd != null && this._hoverStart != null)
            {
                foreach (DateTime item in this.SelectedDates)
                {
                    this._removedItems.Add(item);
                }

                this.SelectedDates.ClearInternal();
                //In keyboard selection, we are sure that the collection does not include any blackout days
                this.SelectedDates.AddRange(this._hoverStart.Value, this.HoverEnd.Value);
            }
        }

        private void Calendar_GotFocus(object sender, RoutedEventArgs e)
        {
            Calendar c = sender as Calendar;
            Debug.Assert(c != null);
            this._hasFocus = true;

            switch (this.DisplayMode)
            {
                case CalendarMode.Month:
                    {
                        DateTime focusDate;
                        if (this.LastSelectedDate.HasValue && DateTimeHelper.CompareYearMonth(this.DisplayDateInternal, this.LastSelectedDate.Value) == 0)
                        {
                            focusDate = this.LastSelectedDate.Value;
                        }
                        else
                        {
                            focusDate = this.DisplayDate;
                            this.LastSelectedDate = this.DisplayDate;
                        }
                        Debug.Assert(focusDate != null);
                        this._focusButton = FindDayButtonFromDay(focusDate);

                        if (this._focusButton != null)
                        {
                            this._focusButton.IsCurrent = true;
                        }
                        break;
                    }
                case CalendarMode.Year:
                case CalendarMode.Decade:
                    {
                        this.FocusCalendarButton.IsFocusedOverride = true;
                        break;
                    }
            }
        }

        private void Calendar_KeyDown(object sender, KeyEventArgs e)
        {
            Calendar c = sender as Calendar;
            Debug.Assert(c != null);

            if (!e.Handled && c.IsEnabled)
            {
                e.Handled = ProcessCalendarKey(e);
            }
        }

        private void Calendar_KeyUp(object sender, KeyEventArgs e)
        {
            if (!e.Handled && e.Key == Key.Shift)
            {
                ProcessShiftKeyUp();
            }
        }

        private void Calendar_LostFocus(object sender, RoutedEventArgs e)
        {
            Calendar c = sender as Calendar;
            Debug.Assert(c != null);
            this._hasFocus = false;

            switch (this.DisplayMode)
            {
                case CalendarMode.Month:
                    {
                        if (this._focusButton != null)
                        {
                            this._focusButton.IsCurrent = false;
                        }
                        break;
                    }
                case CalendarMode.Year:
                case CalendarMode.Decade:
                    {
                        if (this.FocusCalendarButton != null)
                        {
                            this.FocusCalendarButton.IsFocusedOverride = false;
                        }
                        break;
                    }
            }
        }

        private void Calendar_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            if (!this._hasFocus)
            {
                this.Focus();
            }
        }

        private void Calendar_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            Debug.Assert(sender is Calendar);

            RectangleGeometry rg = new RectangleGeometry();
            rg.Rect = new Rect(0, 0, e.NewSize.Width, e.NewSize.Height);

            if (_root != null)
            {
                _root.Clip = rg;
            }
        }

        private static void EnsureCalendarButtonStyle(CalendarButton calendarButton, Style oldCalendarButtonStyle, Style newCalendarButtonStyle)
        {
            Debug.Assert(calendarButton != null);

            if (newCalendarButtonStyle != null)
            {
                // 

                if (calendarButton != null && (calendarButton.Style == null || calendarButton.Style == oldCalendarButtonStyle))
                {
                    calendarButton.Style = newCalendarButtonStyle;
                }
            }
        }

        private static void EnsureDayButtonStyle(CalendarDayButton dayButton, Style oldDayButtonStyle, Style newDayButtonStyle)
        {
            Debug.Assert(dayButton != null);

            if (newDayButtonStyle != null)
            {
                // 

                if (dayButton != null && (dayButton.Style == null || dayButton.Style == oldDayButtonStyle))
                {
                    dayButton.Style = newDayButtonStyle;
                }
            }
        }

        private static void EnsureMonthStyle(CalendarItem month, Style oldMonthStyle, Style newMonthStyle)
        {
            Debug.Assert(month != null);

            if (newMonthStyle != null)
            {
                // 

                if (month != null && (month.Style == null || month.Style == oldMonthStyle))
                {
                    month.Style = newMonthStyle;
                }
            }
        }

        private static bool IsSelectionChanged(SelectionChangedEventArgs e)
        {
            if (e.AddedItems.Count != e.RemovedItems.Count)
            {
                return true;
            }
            foreach (DateTime addedDate in e.AddedItems)
            {
                if (!e.RemovedItems.Contains(addedDate))
                {
                    return true;
                }
            }
            return false;
        }

        private static bool IsValidDisplayMode(CalendarMode mode)
        {
            return mode == CalendarMode.Month
                || mode == CalendarMode.Year
                || mode == CalendarMode.Decade;
        }

        private static bool IsValidFirstDayOfWeek(object value)
        {
            DayOfWeek day = (DayOfWeek)value;

            return day == DayOfWeek.Sunday
                || day == DayOfWeek.Monday
                || day == DayOfWeek.Tuesday
                || day == DayOfWeek.Wednesday
                || day == DayOfWeek.Thursday
                || day == DayOfWeek.Friday
                || day == DayOfWeek.Saturday;
        }

        private static bool IsValidKeyboardSelection(Calendar cal, object value)
        {
            if (value == null)
            {
                return true;
            }
            else
            {
                if (cal.BlackoutDates.Contains((DateTime)value))
                {
                    return false;
                }
                else
                {
                    return (DateTime.Compare((DateTime)value, cal.DisplayDateRangeStart) >= 0 && DateTime.Compare((DateTime)value, cal.DisplayDateRangeEnd) <= 0);
                }
            }
        }

        private static bool IsValidSelectionMode(object value)
        {
            CalendarSelectionMode mode = (CalendarSelectionMode)value;

            return mode == CalendarSelectionMode.SingleDate
                || mode == CalendarSelectionMode.SingleRange
                || mode == CalendarSelectionMode.MultipleRange
                || mode == CalendarSelectionMode.None;
        }

        private void OnDisplayDate(CalendarDateChangedEventArgs e)
        {
            EventHandler<CalendarDateChangedEventArgs> handler = this.DisplayDateChanged;
            if (null != handler)
            {
                handler(this, e);
            }
        }

        private void OnDisplayModeChanged(CalendarModeChangedEventArgs args)
        {
            EventHandler<CalendarModeChangedEventArgs> handler = this.DisplayModeChanged;

            if (null != handler)
            {
                handler(this, args);
            }
        }

        private void OnHeaderClick()
        {
            Debug.Assert(this.DisplayMode == CalendarMode.Year || this.DisplayMode == CalendarMode.Decade);
            CalendarItem monthControl = this.MonthControl;
            if (monthControl != null)
            {
                monthControl.MonthView.Visibility = Visibility.Collapsed;
                monthControl.YearView.Visibility = Visibility.Visible;
                this.UpdateMonths();
            }
        }

        private void OnMonthClick()
        {
            CalendarItem monthControl = this.MonthControl;
            if (monthControl != null)
            {
                monthControl.YearView.Visibility = Visibility.Collapsed;
                monthControl.MonthView.Visibility = Visibility.Visible;

                if (!this.LastSelectedDate.HasValue || DateTimeHelper.CompareYearMonth(this.LastSelectedDate.Value, this.DisplayDate) != 0)
                {
                    this.LastSelectedDate = this.DisplayDate;
                }

                this.UpdateMonths();
            }
        }

        private void OnSelectedMonthChanged(DateTime? selectedMonth)
        {
            if (selectedMonth.HasValue)
            {
                Debug.Assert(this.DisplayMode == CalendarMode.Year);
                this.SelectedMonth = selectedMonth.Value;
                UpdateMonths();
            }
        }

        private void OnSelectedYearChanged(DateTime? selectedYear)
        {
            if (selectedYear.HasValue)
            {
                Debug.Assert(this.DisplayMode == CalendarMode.Decade);
                this.SelectedYear = selectedYear.Value;
                UpdateMonths();
            }
        }

        private bool ProcessCalendarKey(KeyEventArgs e)
        {
            if (this.DisplayMode == CalendarMode.Month)
            {
                if (this.LastSelectedDate.HasValue && this.DisplayDateInternal != null)
                {
                    //If a blackout day is inactive, when clicked on it, the previous inactive day which is not a blackout day can get the focus.
                    //In this case we should allow keyboard functions on that inactive day
                    if (DateTimeHelper.CompareYearMonth(this.LastSelectedDate.Value, this.DisplayDateInternal) != 0 && this._focusButton != null && !this._focusButton.IsInactive)
                    {
                        return true;
                    }
                }
            }

            bool ctrl, shift;
            KeyboardHelper.GetMetaKeyState(out ctrl, out shift);

            switch (e.Key)
            {
                case Key.Up:
                    {
                        ProcessUpKey(ctrl, shift);
                        return true;
                    }
                case Key.Down:
                    {
                        ProcessDownKey(ctrl, shift);
                        return true;
                    }
                case Key.Left:
                    {
                        ProcessLeftKey(shift);
                        return true;
                    }
                case Key.Right:
                    {
                        ProcessRightKey(shift);
                        return true;
                    }
                case Key.PageDown:
                    {
                        ProcessPageDownKey(shift);
                        return true;
                    }
                case Key.PageUp:
                    {
                        ProcessPageUpKey(shift);
                        return true;
                    }
                case Key.Home:
                    {
                        ProcessHomeKey(shift);
                        return true;
                    }
                case Key.End:
                    {
                        ProcessEndKey(shift);
                        return true;
                    }
                case Key.Enter:
                case Key.Space:
                    {
                        return ProcessEnterKey();
                    }

            }
            return false;
        }

        private void ProcessDownKey(bool ctrl, bool shift)
        {
            switch (this.DisplayMode)
            {
                case CalendarMode.Month:
                    {
                        if (!ctrl || shift)
                        {
                            DateTime? selectedDate = DateTimeHelper.AddDays(this.LastSelectedDate.GetValueOrDefault(DateTime.Today), COLS);
                            ProcessSelection(shift, selectedDate, COLS);
                        }
                        break;
                    }
                case CalendarMode.Year:
                    {
                        if (ctrl)
                        {
                            this.DisplayDate = this.SelectedMonth;
                            this.DisplayMode = CalendarMode.Month;
                        }
                        else
                        {
                            DateTime? selectedMonth = DateTimeHelper.AddMonths(this._selectedMonth, YEAR_COLS);
                            OnSelectedMonthChanged(selectedMonth);
                        }
                        break;
                    }
                case CalendarMode.Decade:
                    {
                        if (ctrl)
                        {
                            this.SelectedMonth = this.SelectedYear;
                            this.DisplayMode = CalendarMode.Year;
                        }
                        else
                        {
                            DateTime? selectedYear = DateTimeHelper.AddYears(this.SelectedYear, YEAR_COLS);
                            OnSelectedYearChanged(selectedYear);
                        }
                        break;
                    }
            }
        }

        private void ProcessEndKey(bool shift)
        {
            switch (this.DisplayMode)
            {
                case CalendarMode.Month:
                    {
                        if (this.DisplayDate != null)
                        {
                            DateTime? selectedDate = new DateTime((this.DisplayDateInternal).Year, (this.DisplayDateInternal).Month, 1);

                            if (DateTimeHelper.CompareYearMonth(DateTime.MaxValue, selectedDate.Value) > 0)
                            {
                                //since DisplayDate is not equal to DateTime.MaxValue we are sure selectedDate is not null
                                selectedDate = DateTimeHelper.AddMonths(selectedDate.Value, 1).Value;
                                selectedDate = DateTimeHelper.AddDays(selectedDate.Value, -1).Value;
                            }
                            else
                            {
                                selectedDate = DateTime.MaxValue;
                            }
                            ProcessSelection(shift, selectedDate, null);
                        }
                        break;
                    }
                case CalendarMode.Year:
                    {
                        DateTime selectedMonth = new DateTime(this._selectedMonth.Year, 12, 1);
                        OnSelectedMonthChanged(selectedMonth);
                        break;
                    }
                case CalendarMode.Decade:
                    {
                        DateTime? selectedYear = new DateTime(DateTimeHelper.EndOfDecade(this.SelectedYear), 1, 1);
                        OnSelectedYearChanged(selectedYear);
                        break;
                    }
            }
        }

        private bool ProcessEnterKey()
        {
            switch (this.DisplayMode)
            {
                case CalendarMode.Year:
                    {
                        this.DisplayDate = this.SelectedMonth;
                        this.DisplayMode = CalendarMode.Month;
                        return true;
                    }
                case CalendarMode.Decade:
                    {
                        this.SelectedMonth = this.SelectedYear;
                        this.DisplayMode = CalendarMode.Year;
                        return true;
                    }
            }
            return false;
        }

        private void ProcessHomeKey(bool shift)
        {
            switch (this.DisplayMode)
            {
                case CalendarMode.Month:
                    {
                        // 
                        DateTime? selectedDate = new DateTime((this.DisplayDateInternal).Year, (this.DisplayDateInternal).Month, 1);
                        ProcessSelection(shift, selectedDate, null);
                        break;
                    }
                case CalendarMode.Year:
                    {
                        DateTime selectedMonth = new DateTime(this._selectedMonth.Year, 1, 1);
                        OnSelectedMonthChanged(selectedMonth);
                        break;
                    }
                case CalendarMode.Decade:
                    {
                        DateTime? selectedYear = new DateTime(DateTimeHelper.DecadeOfDate(this.SelectedYear), 1, 1);
                        OnSelectedYearChanged(selectedYear);
                        break;
                    }
            }
        }

        private void ProcessLeftKey(bool shift)
        {
            switch (this.DisplayMode)
            {
                case CalendarMode.Month:
                    {
                        DateTime? selectedDate = DateTimeHelper.AddDays(this.LastSelectedDate.GetValueOrDefault(DateTime.Today), -1);
                        ProcessSelection(shift, selectedDate, -1);
                        break;
                    }
                case CalendarMode.Year:
                    {
                        DateTime? selectedMonth = DateTimeHelper.AddMonths(this._selectedMonth, -1);
                        OnSelectedMonthChanged(selectedMonth);
                        break;
                    }
                case CalendarMode.Decade:
                    {
                        DateTime? selectedYear = DateTimeHelper.AddYears(this.SelectedYear, -1);
                        OnSelectedYearChanged(selectedYear);
                        break;
                    }
            }
        }

        private void ProcessPageDownKey(bool shift)
        {
            switch (this.DisplayMode)
            {
                case CalendarMode.Month:
                    {
                        DateTime? selectedDate = DateTimeHelper.AddMonths(this.LastSelectedDate.GetValueOrDefault(DateTime.Today), 1);
                        ProcessSelection(shift, selectedDate, null);
                        break;
                    }
                case CalendarMode.Year:
                    {
                        DateTime? selectedMonth = DateTimeHelper.AddYears(this._selectedMonth, 1);
                        OnSelectedMonthChanged(selectedMonth);
                        break;
                    }
                case CalendarMode.Decade:
                    {
                        DateTime? selectedYear = DateTimeHelper.AddYears(this.SelectedYear, 10);
                        OnSelectedYearChanged(selectedYear);
                        break;
                    }
            }
        }

        private void ProcessPageUpKey(bool shift)
        {
            switch (this.DisplayMode)
            {
                case CalendarMode.Month:
                    {
                        DateTime? selectedDate = DateTimeHelper.AddMonths(this.LastSelectedDate.GetValueOrDefault(DateTime.Today), -1);
                        ProcessSelection(shift, selectedDate, null);
                        break;
                    }
                case CalendarMode.Year:
                    {
                        DateTime? selectedMonth = DateTimeHelper.AddYears(this._selectedMonth, -1);
                        OnSelectedMonthChanged(selectedMonth);
                        break;
                    }
                case CalendarMode.Decade:
                    {
                        DateTime? selectedYear = DateTimeHelper.AddYears(this.SelectedYear, -10);
                        OnSelectedYearChanged(selectedYear);
                        break;
                    }
            }
        }

        private void ProcessRightKey(bool shift)
        {
            switch (this.DisplayMode)
            {
                case CalendarMode.Month:
                    {
                        DateTime? selectedDate = DateTimeHelper.AddDays(this.LastSelectedDate.GetValueOrDefault(DateTime.Today), 1);
                        ProcessSelection(shift, selectedDate, 1);
                        break;
                    }
                case CalendarMode.Year:
                    {
                        DateTime? selectedMonth = DateTimeHelper.AddMonths(this._selectedMonth, 1);
                        OnSelectedMonthChanged(selectedMonth);
                        break;
                    }
                case CalendarMode.Decade:
                    {
                        DateTime? selectedYear = DateTimeHelper.AddYears(this.SelectedYear, 1);
                        OnSelectedYearChanged(selectedYear);
                        break;
                    }
            }
        }

        private void ProcessSelection(bool shift, DateTime? lastSelectedDate, int? index)
        {
            if (this.SelectionMode == CalendarSelectionMode.None && lastSelectedDate != null)
            {
                OnDayClick(lastSelectedDate.Value);
                return;
            }
            if (lastSelectedDate != null && IsValidKeyboardSelection(this, lastSelectedDate.Value))
            {
                if (this.SelectionMode == CalendarSelectionMode.SingleRange || this.SelectionMode == CalendarSelectionMode.MultipleRange)
                {
                    foreach (DateTime item in this.SelectedDates)
                    {
                        this._removedItems.Add(item);
                    }
                    this.SelectedDates.ClearInternal();
                    if (shift)
                    {
                        CalendarDayButton b;
                        _isShiftPressed = true;
                        if (this._hoverStart == null)
                        {
                            if (this.LastSelectedDate != null)
                            {
                                this._hoverStart = this.LastSelectedDate;
                            }
                            else
                            {
                                if (DateTimeHelper.CompareYearMonth(this.DisplayDateInternal, DateTime.Today) == 0)
                                {
                                    this._hoverStart = DateTime.Today;
                                }
                                else
                                {
                                    this._hoverStart = this.DisplayDateInternal;
                                }
                            }

                            b = FindDayButtonFromDay(this._hoverStart.Value);
                            if (b != null)
                            {
                                this._hoverStartIndex = b.Index;
                            }
                        }
                        //the index of the SelectedDate is always the last selectedDate's index
                        UnHighlightDays();
                        //If we hit a BlackOutDay with keyboard we do not update the HoverEnd
                        CalendarDateRange range;

                        if (DateTime.Compare(this._hoverStart.Value, lastSelectedDate.Value) < 0)
                        {
                            range = new CalendarDateRange(this._hoverStart.Value, lastSelectedDate.Value);
                        }
                        else
                        {
                            range = new CalendarDateRange(lastSelectedDate.Value, this._hoverStart.Value);
                        }

                        if (!this.BlackoutDates.ContainsAny(range))
                        {
                            this.HoverEnd = lastSelectedDate;

                            if (index.HasValue)
                            {
                                this._hoverEndIndex += index;
                            }
                            else
                            {
                                //
                                b = FindDayButtonFromDay(this._hoverEnd.Value);

                                if (b != null)
                                {
                                    this._hoverEndIndex = b.Index;
                                }
                            }
                        }

                        OnDayClick(this.HoverEnd.Value);
                        HighlightDays();
                    }
                    else
                    {
                        this._hoverStart = lastSelectedDate;
                        this.HoverEnd = lastSelectedDate;
                        AddSelection();
                        OnDayClick(lastSelectedDate.Value);
                    }
                }
                else
                {
                    //ON CLEAR 
                    this.LastSelectedDate = lastSelectedDate.Value;
                    if (this.SelectedDates.Count > 0)
                    {
                        this.SelectedDates[0] = lastSelectedDate.Value;
                    }
                    else
                    {
                        this.SelectedDates.Add(lastSelectedDate.Value);
                    }
                    OnDayClick(lastSelectedDate.Value);
                }
            }
        }

        private void ProcessShiftKeyUp()
        {
            if (_isShiftPressed && (this.SelectionMode == CalendarSelectionMode.SingleRange || this.SelectionMode == CalendarSelectionMode.MultipleRange))
            {
                AddSelection();
                _isShiftPressed = false;
            }
        }

        private void ProcessUpKey(bool ctrl, bool shift)
        {
            switch (this.DisplayMode)
            {
                case CalendarMode.Month:
                    {
                        if (ctrl)
                        {
                            this.SelectedMonth = this.DisplayDateInternal;
                            this.DisplayMode = CalendarMode.Year;
                        }
                        else
                        {
                            DateTime? selectedDate = DateTimeHelper.AddDays(this.LastSelectedDate.GetValueOrDefault(DateTime.Today), -COLS);
                            ProcessSelection(shift, selectedDate, -COLS);
                        }
                        break;
                    }
                case CalendarMode.Year:
                    {
                        if (ctrl)
                        {
                            this.SelectedYear = this.SelectedMonth;
                            this.DisplayMode = CalendarMode.Decade;
                        }
                        else
                        {
                            DateTime? selectedMonth = DateTimeHelper.AddMonths(this._selectedMonth, -YEAR_COLS);
                            OnSelectedMonthChanged(selectedMonth);
                        }
                        break;
                    }
                case CalendarMode.Decade:
                    {
                        if (!ctrl)
                        {
                            DateTime? selectedYear = DateTimeHelper.AddYears(this.SelectedYear, -YEAR_COLS);
                            OnSelectedYearChanged(selectedYear);
                        }
                        break;
                    }
            }
        }

        private static DateTime? SelectedDateMax(Calendar cal)
        {
            DateTime selectedDateMax;

            if (cal.SelectedDates.Count > 0)
            {
                selectedDateMax = cal.SelectedDates[0];
                Debug.Assert(DateTime.Compare(cal.SelectedDate.Value, selectedDateMax) == 0);
            }
            else
            {
                return null;
            }

            foreach (DateTime selectedDate in cal.SelectedDates)
            {
                if (DateTime.Compare(selectedDate, selectedDateMax) > 0)
                {
                    selectedDateMax = selectedDate;
                }
            }
            return selectedDateMax;
        }

        private static DateTime? SelectedDateMin(Calendar cal)
        {
            DateTime selectedDateMin;

            if (cal.SelectedDates.Count > 0)
            {
                selectedDateMin = cal.SelectedDates[0];
                Debug.Assert(DateTime.Compare(cal.SelectedDate.Value, selectedDateMin) == 0);
            }
            else
            {
                return null;
            }

            foreach (DateTime selectedDate in cal.SelectedDates)
            {
                if (DateTime.Compare(selectedDate, selectedDateMin) < 0)
                {
                    selectedDateMin = selectedDate;
                }
            }
            return selectedDateMin;
        }

        internal void SortHoverIndexes(out int startIndex, out int endIndex)
        {
            //not comparing indexes since the two days may not be on the same month
            // 


            if (DateTimeHelper.CompareDays(this.HoverEnd.Value, this._hoverStart.Value) > 0)
            {
                startIndex = this._hoverStartIndex.Value;
                endIndex = this._hoverEndIndex.Value;
            }
            else
            {
                startIndex = this._hoverEndIndex.Value;
                endIndex = this._hoverStartIndex.Value;
            }
        }

        #endregion Private Methods
    }
}
www.java2v.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.