Code:
/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Framework / System / Windows / Controls / Primitives / CalendarItem.cs / 1305600 / CalendarItem.cs
//---------------------------------------------------------------------------- // // Copyright (C) Microsoft Corporation. All rights reserved. // //--------------------------------------------------------------------------- using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Input; namespace System.Windows.Controls.Primitives { [TemplatePart(Name = CalendarItem.ElementRoot, Type = typeof(FrameworkElement))] [TemplatePart(Name = CalendarItem.ElementHeaderButton, Type = typeof(Button))] [TemplatePart(Name = CalendarItem.ElementPreviousButton, Type = typeof(Button))] [TemplatePart(Name = CalendarItem.ElementNextButton, Type = typeof(Button))] [TemplatePart(Name = CalendarItem.ElementDayTitleTemplate, Type = typeof(DataTemplate))] [TemplatePart(Name = CalendarItem.ElementMonthView, Type = typeof(Grid))] [TemplatePart(Name = CalendarItem.ElementYearView, Type = typeof(Grid))] [TemplatePart(Name = CalendarItem.ElementDisabledVisual, Type = typeof(FrameworkElement))] public sealed partial class CalendarItem : Control { #region Constants private const string ElementRoot = "PART_Root"; private const string ElementHeaderButton = "PART_HeaderButton"; private const string ElementPreviousButton = "PART_PreviousButton"; private const string ElementNextButton = "PART_NextButton"; private const string ElementDayTitleTemplate = "DayTitleTemplate"; private const string ElementMonthView = "PART_MonthView"; private const string ElementYearView = "PART_YearView"; private const string ElementDisabledVisual = "PART_DisabledVisual"; private const int COLS = 7; private const int ROWS = 7; private const int YEAR_COLS = 4; private const int YEAR_ROWS = 3; private const int NUMBER_OF_DAYS_IN_WEEK = 7; #endregion Constants #region Data private static ComponentResourceKey _dayTitleTemplateResourceKey = null; private System.Globalization.Calendar _calendar = new GregorianCalendar(); private DataTemplate _dayTitleTemplate; private FrameworkElement _disabledVisual; private Button _headerButton; private Grid _monthView; private Button _nextButton; private Button _previousButton; private Grid _yearView; private bool _isMonthPressed; private bool _isDayPressed; #endregion Data static CalendarItem() { DefaultStyleKeyProperty.OverrideMetadata(typeof(CalendarItem), new FrameworkPropertyMetadata(typeof(CalendarItem))); FocusableProperty.OverrideMetadata(typeof(CalendarItem), new FrameworkPropertyMetadata(false)); KeyboardNavigation.TabNavigationProperty.OverrideMetadata(typeof(CalendarItem), new FrameworkPropertyMetadata(KeyboardNavigationMode.Once)); KeyboardNavigation.DirectionalNavigationProperty.OverrideMetadata(typeof(CalendarItem), new FrameworkPropertyMetadata(KeyboardNavigationMode.Contained)); IsEnabledProperty.OverrideMetadata(typeof(CalendarItem), new UIPropertyMetadata(new PropertyChangedCallback(OnVisualStatePropertyChanged))); } ////// Represents the month that is used in Calendar Control. /// public CalendarItem() { } #region Internal Properties internal Grid MonthView { get { return _monthView; } } internal Calendar Owner { get; set; } internal Grid YearView { get { return _yearView; } } #endregion Internal Properties #region Private Properties ////// Gets a value indicating whether the calendar is displayed in months, years or decades. /// private CalendarMode DisplayMode { get { return (this.Owner != null) ? this.Owner.DisplayMode : CalendarMode.Month; } } internal Button HeaderButton { get { return this._headerButton; } } internal Button NextButton { get { return this._nextButton; } } internal Button PreviousButton { get { return this._previousButton; } } private DateTime DisplayDate { get { return (Owner != null) ? Owner.DisplayDate : DateTime.Today; } } #endregion Private Properties #region Public Methods ////// Invoked whenever application code or an internal process, /// such as a rebuilding layout pass, calls the ApplyTemplate method. /// public override void OnApplyTemplate() { base.OnApplyTemplate(); if (this._previousButton != null) { this._previousButton.Click -= new RoutedEventHandler(PreviousButton_Click); } if (this._nextButton != null) { this._nextButton.Click -= new RoutedEventHandler(NextButton_Click); } if (this._headerButton != null) { this._headerButton.Click -= new RoutedEventHandler(HeaderButton_Click); } _monthView = GetTemplateChild(ElementMonthView) as Grid; _yearView = GetTemplateChild(ElementYearView) as Grid; _previousButton = GetTemplateChild(ElementPreviousButton) as Button; _nextButton = GetTemplateChild(ElementNextButton) as Button; _headerButton = GetTemplateChild(ElementHeaderButton) as Button; _disabledVisual = GetTemplateChild(ElementDisabledVisual) as FrameworkElement; // WPF Compat: Unlike SL, WPF is not able to get elements in template resources with GetTemplateChild() _dayTitleTemplate = null; if (Template != null && Template.Resources.Contains(DayTitleTemplateResourceKey)) { _dayTitleTemplate = Template.Resources[DayTitleTemplateResourceKey] as DataTemplate; } if (this._previousButton != null) { // If the user does not provide a Content value in template, we provide a helper text that can be used in Accessibility // this text is not shown on the UI, just used for Accessibility purposes if (this._previousButton.Content == null) { this._previousButton.Content = SR.Get(SRID.Calendar_PreviousButtonName); } this._previousButton.Click += new RoutedEventHandler(PreviousButton_Click); } if (this._nextButton != null) { // If the user does not provide a Content value in template, we provide a helper text that can be used in Accessibility // this text is not shown on the UI, just used for Accessibility purposes if (this._nextButton.Content == null) { this._nextButton.Content = SR.Get(SRID.Calendar_NextButtonName); } this._nextButton.Click += new RoutedEventHandler(NextButton_Click); } if (this._headerButton != null) { this._headerButton.Click += new RoutedEventHandler(HeaderButton_Click); } PopulateGrids(); if (this.Owner != null) { switch (this.Owner.DisplayMode) { case CalendarMode.Year: UpdateYearMode(); break; case CalendarMode.Decade: UpdateDecadeMode(); break; case CalendarMode.Month: UpdateMonthMode(); break; default: Debug.Assert(false); break; } } else { UpdateMonthMode(); } } #endregion Public Methods #region Protected Methods internal override void ChangeVisualState(bool useTransitions) { if (!IsEnabled) { VisualStateManager.GoToState(this, VisualStates.StateDisabled, useTransitions); } else { VisualStateManager.GoToState(this, VisualStates.StateNormal, useTransitions); } base.ChangeVisualState(useTransitions); } protected override void OnMouseUp(MouseButtonEventArgs e) { base.OnMouseUp(e); if (this.IsMouseCaptured) { this.ReleaseMouseCapture(); } this._isMonthPressed = false; this._isDayPressed = false; // In Month mode, we may need to end a drag selection even if the mouse up isn't on the calendar. if (!e.Handled && this.Owner.DisplayMode == CalendarMode.Month && this.Owner.HoverEnd.HasValue) { FinishSelection(this.Owner.HoverEnd.Value); } } protected override void OnLostMouseCapture(MouseEventArgs e) { base.OnLostMouseCapture(e); if (!this.IsMouseCaptured) { this._isDayPressed = false; this._isMonthPressed = false; } } #endregion #region Internal Methods internal void UpdateDecadeMode() { DateTime selectedYear; if (this.Owner != null) { selectedYear = this.Owner.DisplayYear; } else { selectedYear = DateTime.Today; } int decade = GetDecadeForDecadeMode(selectedYear); int decadeEnd = decade + 9; SetDecadeModeHeaderButton(decade); SetDecadeModePreviousButton(decade); SetDecadeModeNextButton(decadeEnd); if (_yearView != null) { SetYearButtons(decade, decadeEnd); } } internal void UpdateMonthMode() { SetMonthModeHeaderButton(); SetMonthModePreviousButton(); SetMonthModeNextButton(); if (_monthView != null) { SetMonthModeDayTitles(); SetMonthModeCalendarDayButtons(); AddMonthModeHighlight(); } } internal void UpdateYearMode() { SetYearModeHeaderButton(); SetYearModePreviousButton(); SetYearModeNextButton(); if (_yearView != null) { SetYearModeMonthButtons(); } } internal IEnumerableGetCalendarDayButtons() { // int count = ROWS * COLS; if (MonthView != null) { UIElementCollection dayButtonsHost = MonthView.Children; for (int childIndex = COLS; childIndex < count; childIndex++) { CalendarDayButton b = dayButtonsHost[childIndex] as CalendarDayButton; if (b != null) { yield return b; } } } } internal CalendarDayButton GetFocusedCalendarDayButton() { foreach (CalendarDayButton b in GetCalendarDayButtons()) { if (b != null && b.IsFocused) { return b; } } return null; } internal CalendarDayButton GetCalendarDayButton(DateTime date) { foreach (CalendarDayButton b in GetCalendarDayButtons()) { if (b != null && b.DataContext is DateTime) { if (DateTimeHelper.CompareDays(date, (DateTime)b.DataContext) == 0) { return b; } } } return null; } internal CalendarButton GetCalendarButton(DateTime date, CalendarMode mode) { Debug.Assert(mode != CalendarMode.Month); foreach (CalendarButton b in GetCalendarButtons()) { if (b != null && b.DataContext is DateTime) { if (mode == CalendarMode.Year) { if (DateTimeHelper.CompareYearMonth(date, (DateTime)b.DataContext) == 0) { return b; } } else { if (date.Year == ((DateTime)b.DataContext).Year) { return b; } } } } return null; } internal CalendarButton GetFocusedCalendarButton() { foreach (CalendarButton b in GetCalendarButtons()) { if (b != null && b.IsFocused) { return b; } } return null; } private IEnumerable GetCalendarButtons() { foreach (UIElement element in this.YearView.Children) { CalendarButton b = element as CalendarButton; if (b != null) { yield return b; } } } internal void FocusDate(DateTime date) { FrameworkElement focusTarget = null; switch (this.DisplayMode) { case CalendarMode.Month: { focusTarget = GetCalendarDayButton(date); break; } case CalendarMode.Year: case CalendarMode.Decade: { focusTarget = GetCalendarButton(date, this.DisplayMode); break; } default: { Debug.Assert(false); break; } } if (focusTarget != null && !focusTarget.IsFocused) { focusTarget.MoveFocus(new TraversalRequest(FocusNavigationDirection.First)); } } #endregion Internal Methods #region Private Methods private int GetDecadeForDecadeMode(DateTime selectedYear) { int decade = DateTimeHelper.DecadeOfDate(selectedYear); // Adjust the decade value if the mouse move selection is on, // such that if first or last year among the children are selected // then return the current selected decade as is. if (_isMonthPressed && _yearView != null) { UIElementCollection yearViewChildren = _yearView.Children; int count = yearViewChildren.Count; if (count > 0) { CalendarButton child = yearViewChildren[0] as CalendarButton; if (child != null && child.DataContext is DateTime && ((DateTime)child.DataContext).Year == selectedYear.Year) { return (decade + 10); } } if (count > 1) { CalendarButton child = yearViewChildren[count - 1] as CalendarButton; if (child != null && child.DataContext is DateTime && ((DateTime)child.DataContext).Year == selectedYear.Year) { return (decade - 10); } } } return decade; } private void EndDrag(bool ctrl, DateTime selectedDate) { if (this.Owner != null) { this.Owner.CurrentDate = selectedDate; if (this.Owner.HoverStart.HasValue) { if ( ctrl && DateTime.Compare(this.Owner.HoverStart.Value, selectedDate) == 0 && (Owner.SelectionMode == CalendarSelectionMode.SingleDate || Owner.SelectionMode == CalendarSelectionMode.MultipleRange)) { // Ctrl + single click = toggle this.Owner.SelectedDates.Toggle(selectedDate); } else { // this is selection with Mouse, we do not guarantee the range does not include BlackOutDates. // Use the internal AddRange that omits BlackOutDates based on the SelectionMode this.Owner.SelectedDates.AddRangeInternal(this.Owner.HoverStart.Value, selectedDate); } Owner.OnDayClick(selectedDate); } } } private void CellOrMonth_PreviewKeyDown(object sender, RoutedEventArgs e) { Debug.Assert(e != null); if (this.Owner == null) { return; } this.Owner.OnDayOrMonthPreviewKeyDown(e); } private void Cell_Clicked(object sender, RoutedEventArgs e) { if (this.Owner == null) { return; } CalendarDayButton b = sender as CalendarDayButton; Debug.Assert(b != null); if (!(b.DataContext is DateTime)) { return; } // If the day is a blackout day selection is not allowed if (!b.IsBlackedOut) { DateTime clickedDate = (DateTime)b.DataContext; bool ctrl, shift; CalendarKeyboardHelper.GetMetaKeyState(out ctrl, out shift); switch (this.Owner.SelectionMode) { case CalendarSelectionMode.None: { break; } case CalendarSelectionMode.SingleDate: { if (!ctrl) { this.Owner.SelectedDate = clickedDate; } else { this.Owner.SelectedDates.Toggle(clickedDate); } break; } case CalendarSelectionMode.SingleRange: { DateTime? lastDate = this.Owner.CurrentDate; this.Owner.SelectedDates.ClearInternal(true /*fireChangeNotification*/); if (shift && lastDate.HasValue) { this.Owner.SelectedDates.AddRangeInternal(lastDate.Value, clickedDate); } else { this.Owner.SelectedDate = clickedDate; this.Owner.HoverStart = null; this.Owner.HoverEnd = null; } break; } case CalendarSelectionMode.MultipleRange: { if (!ctrl) { this.Owner.SelectedDates.ClearInternal(true /*fireChangeNotification*/); } if (shift) { this.Owner.SelectedDates.AddRangeInternal(this.Owner.CurrentDate, clickedDate); } else { if (!ctrl) { this.Owner.SelectedDate = clickedDate; } else { this.Owner.SelectedDates.Toggle(clickedDate); this.Owner.HoverStart = null; this.Owner.HoverEnd = null; } } break; } } this.Owner.OnDayClick(clickedDate); } } private void Cell_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { CalendarDayButton b = sender as CalendarDayButton; if (b == null) { return; } if (this.Owner == null || !(b.DataContext is DateTime)) { return; } if (b.IsBlackedOut) { this.Owner.HoverStart = null; } else { this._isDayPressed = true; Mouse.Capture(this, CaptureMode.SubTree); b.MoveFocus(new TraversalRequest(FocusNavigationDirection.First)); bool ctrl, shift; CalendarKeyboardHelper.GetMetaKeyState(out ctrl, out shift); DateTime selectedDate = (DateTime)b.DataContext; Debug.Assert(selectedDate != null); switch (this.Owner.SelectionMode) { case CalendarSelectionMode.None: { break; } case CalendarSelectionMode.SingleDate: { this.Owner.DatePickerDisplayDateFlag = true; if (!ctrl) { this.Owner.SelectedDate = selectedDate; } else { this.Owner.SelectedDates.Toggle(selectedDate); } break; } case CalendarSelectionMode.SingleRange: { this.Owner.SelectedDates.ClearInternal(); if (shift) { if (!this.Owner.HoverStart.HasValue) { this.Owner.HoverStart = this.Owner.HoverEnd = this.Owner.CurrentDate; } } else { this.Owner.HoverStart = this.Owner.HoverEnd = selectedDate; } break; } case CalendarSelectionMode.MultipleRange: { if (!ctrl) { this.Owner.SelectedDates.ClearInternal(); } if (shift) { if (!this.Owner.HoverStart.HasValue) { this.Owner.HoverStart = this.Owner.HoverEnd = this.Owner.CurrentDate; } } else { this.Owner.HoverStart = this.Owner.HoverEnd = selectedDate; } break; } } this.Owner.CurrentDate = selectedDate; this.Owner.UpdateCellItems(); } } private void Cell_MouseEnter(object sender, MouseEventArgs e) { CalendarDayButton b = sender as CalendarDayButton; if (b == null) { return; } if (b.IsBlackedOut) { return; } if (e.LeftButton == MouseButtonState.Pressed && this._isDayPressed) { b.MoveFocus(new TraversalRequest(FocusNavigationDirection.First)); if (this.Owner == null || !(b.DataContext is DateTime)) { return; } DateTime selectedDate = (DateTime)b.DataContext; switch (this.Owner.SelectionMode) { case CalendarSelectionMode.SingleDate: { this.Owner.DatePickerDisplayDateFlag = true; this.Owner.HoverStart = this.Owner.HoverEnd = null; if (this.Owner.SelectedDates.Count == 0) { this.Owner.SelectedDates.Add(selectedDate); } else { this.Owner.SelectedDates[0] = selectedDate; } return; } } this.Owner.HoverEnd = selectedDate; this.Owner.CurrentDate = selectedDate; this.Owner.UpdateCellItems(); } } private void Cell_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) { CalendarDayButton b = sender as CalendarDayButton; if (b == null) { return; } if (this.Owner == null) { return; } if (!b.IsBlackedOut) { this.Owner.OnDayButtonMouseUp(e); } if (!(b.DataContext is DateTime)) { return; } FinishSelection((DateTime)b.DataContext); e.Handled = true; } private void FinishSelection(DateTime selectedDate) { bool ctrl, shift; CalendarKeyboardHelper.GetMetaKeyState(out ctrl, out shift); if (this.Owner.SelectionMode == CalendarSelectionMode.None || this.Owner.SelectionMode == CalendarSelectionMode.SingleDate) { this.Owner.OnDayClick(selectedDate); return; } if (this.Owner.HoverStart.HasValue) { switch (this.Owner.SelectionMode) { case CalendarSelectionMode.SingleRange: { // Update SelectedDates this.Owner.SelectedDates.ClearInternal(); EndDrag(ctrl, selectedDate); break; } case CalendarSelectionMode.MultipleRange: { // add the selection (either single day or SingleRange day) EndDrag(ctrl, selectedDate); break; } } } else { // If the day is blacked out but also a trailing day we should be able to switch months CalendarDayButton b = GetCalendarDayButton(selectedDate); if (b != null && b.IsInactive && b.IsBlackedOut) { this.Owner.OnDayClick(selectedDate); } } } private void Month_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { CalendarButton b = sender as CalendarButton; if (b != null) { this._isMonthPressed = true; Mouse.Capture(this, CaptureMode.SubTree); if (this.Owner != null) { this.Owner.OnCalendarButtonPressed(b, false); } } } private void Month_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) { CalendarButton b = sender as CalendarButton; if (b != null && this.Owner != null) { this.Owner.OnCalendarButtonPressed(b, true); } } private void Month_MouseEnter(object sender, MouseEventArgs e) { CalendarButton b = sender as CalendarButton; if (b != null) { if (this._isMonthPressed && this.Owner != null) { this.Owner.OnCalendarButtonPressed(b, false); } } } private void Month_Clicked(object sender, RoutedEventArgs e) { CalendarButton b = sender as CalendarButton; if (b != null) { this.Owner.OnCalendarButtonPressed(b, true); } } private void HeaderButton_Click(object sender, RoutedEventArgs e) { if (this.Owner != null) { if (this.Owner.DisplayMode == CalendarMode.Month) { this.Owner.SetCurrentValueInternal(Calendar.DisplayModeProperty, CalendarMode.Year); } else { Debug.Assert(this.Owner.DisplayMode == CalendarMode.Year); this.Owner.SetCurrentValueInternal(Calendar.DisplayModeProperty, CalendarMode.Decade); } this.FocusDate(this.DisplayDate); } } private void PreviousButton_Click(object sender, RoutedEventArgs e) { if (this.Owner != null) { this.Owner.OnPreviousClick(); } } private void NextButton_Click(object sender, RoutedEventArgs e) { if (this.Owner != null) { this.Owner.OnNextClick(); } } private void PopulateGrids() { if (_monthView != null) { for (int i = 0; i < COLS; i++) { FrameworkElement titleCell = (this._dayTitleTemplate != null) ? (FrameworkElement)this._dayTitleTemplate.LoadContent() : new ContentControl(); titleCell.SetValue(Grid.RowProperty, 0); titleCell.SetValue(Grid.ColumnProperty, i); this._monthView.Children.Add(titleCell); } for (int i = 1; i < ROWS; i++) { for (int j = 0; j < COLS; j++) { CalendarDayButton dayCell = new CalendarDayButton(); dayCell.Owner = this.Owner; dayCell.SetValue(Grid.RowProperty, i); dayCell.SetValue(Grid.ColumnProperty, j); dayCell.SetBinding(CalendarDayButton.StyleProperty, GetOwnerBinding("CalendarDayButtonStyle")); dayCell.AddHandler(CalendarDayButton.MouseLeftButtonDownEvent, new MouseButtonEventHandler(Cell_MouseLeftButtonDown), true); dayCell.AddHandler(CalendarDayButton.MouseLeftButtonUpEvent, new MouseButtonEventHandler(Cell_MouseLeftButtonUp), true); dayCell.AddHandler(CalendarDayButton.MouseEnterEvent, new MouseEventHandler(Cell_MouseEnter), true); dayCell.Click += new RoutedEventHandler(Cell_Clicked); dayCell.AddHandler(PreviewKeyDownEvent, new RoutedEventHandler(CellOrMonth_PreviewKeyDown), true); this._monthView.Children.Add(dayCell); } } } if (_yearView != null) { CalendarButton monthCell; int count = 0; for (int i = 0; i < YEAR_ROWS; i++) { for (int j = 0; j < YEAR_COLS; j++) { monthCell = new CalendarButton(); monthCell.Owner = this.Owner; monthCell.SetValue(Grid.RowProperty, i); monthCell.SetValue(Grid.ColumnProperty, j); monthCell.SetBinding(CalendarButton.StyleProperty, GetOwnerBinding("CalendarButtonStyle")); monthCell.AddHandler(CalendarButton.MouseLeftButtonDownEvent, new MouseButtonEventHandler(Month_MouseLeftButtonDown), true); monthCell.AddHandler(CalendarButton.MouseLeftButtonUpEvent, new MouseButtonEventHandler(Month_MouseLeftButtonUp), true); monthCell.AddHandler(CalendarButton.MouseEnterEvent, new MouseEventHandler(Month_MouseEnter), true); monthCell.AddHandler(UIElement.PreviewKeyDownEvent, new RoutedEventHandler(CellOrMonth_PreviewKeyDown), true); monthCell.Click += new RoutedEventHandler(Month_Clicked); this._yearView.Children.Add(monthCell); count++; } } } } #region Month Mode Display private void SetMonthModeDayTitles() { if (_monthView != null) { string[] shortestDayNames = DateTimeHelper.GetDateFormat(DateTimeHelper.GetCulture(this)).ShortestDayNames; for (int childIndex = 0; childIndex < COLS; childIndex++) { FrameworkElement daytitle = _monthView.Children[childIndex] as FrameworkElement; if (daytitle != null && shortestDayNames != null && shortestDayNames.Length > 0) { if (this.Owner != null) { daytitle.DataContext = shortestDayNames[(childIndex + (int)this.Owner.FirstDayOfWeek) % shortestDayNames.Length]; } else { daytitle.DataContext = shortestDayNames[(childIndex + (int)DateTimeHelper.GetDateFormat( DateTimeHelper.GetCulture(this)).FirstDayOfWeek) % shortestDayNames.Length]; } } } } } private void SetMonthModeCalendarDayButtons() { DateTime firstDayOfMonth = DateTimeHelper.DiscardDayTime(DisplayDate); int lastMonthToDisplay = GetNumberOfDisplayedDaysFromPreviousMonth(firstDayOfMonth); bool isMinMonth = DateTimeHelper.CompareYearMonth(firstDayOfMonth, DateTime.MinValue) <= 0; bool isMaxMonth = DateTimeHelper.CompareYearMonth(firstDayOfMonth, DateTime.MaxValue) >= 0; int daysInMonth = _calendar.GetDaysInMonth(firstDayOfMonth.Year, firstDayOfMonth.Month); CultureInfo culture = DateTimeHelper.GetCulture(this); int count = ROWS * COLS; for (int childIndex = COLS; childIndex < count; childIndex++) { CalendarDayButton childButton = _monthView.Children[childIndex] as CalendarDayButton; Debug.Assert(childButton != null); int dayOffset = childIndex - lastMonthToDisplay - COLS; if ((!isMinMonth || (dayOffset >= 0)) && (!isMaxMonth || (dayOffset < daysInMonth))) { DateTime dateToAdd = _calendar.AddDays(firstDayOfMonth, dayOffset); SetMonthModeDayButtonState(childButton, dateToAdd); childButton.DataContext = dateToAdd; childButton.SetContentInternal(DateTimeHelper.ToDayString(dateToAdd, culture)); } else { SetMonthModeDayButtonState(childButton, null); childButton.DataContext = null; childButton.SetContentInternal(DateTimeHelper.ToDayString(null, culture)); } } } private void SetMonthModeDayButtonState(CalendarDayButton childButton, DateTime? dateToAdd) { if (this.Owner != null) { if (dateToAdd.HasValue) { childButton.Visibility = Visibility.Visible; // If the day is outside the DisplayDateStart/End boundary, do not show it if (DateTimeHelper.CompareDays(dateToAdd.Value, this.Owner.DisplayDateStartInternal) < 0 || DateTimeHelper.CompareDays(dateToAdd.Value, this.Owner.DisplayDateEndInternal) > 0) { childButton.IsEnabled = false; childButton.Visibility = Visibility.Hidden; } else { childButton.IsEnabled = true; // SET IF THE DAY IS SELECTABLE OR NOT childButton.SetValue( CalendarDayButton.IsBlackedOutPropertyKey, this.Owner.BlackoutDates.Contains(dateToAdd.Value)); // SET IF THE DAY IS ACTIVE OR NOT: set if the day is a trailing day or not childButton.SetValue( CalendarDayButton.IsInactivePropertyKey, DateTimeHelper.CompareYearMonth(dateToAdd.Value, this.Owner.DisplayDateInternal) != 0); // SET IF THE DAY IS TODAY OR NOT if (DateTimeHelper.CompareDays(dateToAdd.Value, DateTime.Today) == 0) { childButton.SetValue(CalendarDayButton.IsTodayPropertyKey, true); } else { childButton.SetValue(CalendarDayButton.IsTodayPropertyKey, false); } // the child button doesn't get change notificaitons from Calendar.IsTodayHighlighted // so we need up change visual states to ensure the IsToday is up to date. childButton.NotifyNeedsVisualStateUpdate(); // SET IF THE DAY IS SELECTED OR NOT // Since we should be comparing the Date values not DateTime values, we can't use this.Owner.SelectedDates.Contains(dateToAdd) directly bool isSelected = false; foreach (DateTime item in this.Owner.SelectedDates) { isSelected |= (DateTimeHelper.CompareDays(dateToAdd.Value, item) == 0); } childButton.SetValue(CalendarDayButton.IsSelectedPropertyKey, isSelected); } } else { childButton.Visibility = Visibility.Hidden; childButton.IsEnabled = false; childButton.SetValue(CalendarDayButton.IsBlackedOutPropertyKey, false); childButton.SetValue(CalendarDayButton.IsInactivePropertyKey, true); childButton.SetValue(CalendarDayButton.IsTodayPropertyKey, false); childButton.SetValue(CalendarDayButton.IsSelectedPropertyKey, false); } } } private void AddMonthModeHighlight() { var owner = this.Owner; if (owner == null) { return; } if (owner.HoverStart.HasValue && owner.HoverEnd.HasValue) { DateTime hStart = owner.HoverEnd.Value; DateTime hEnd = owner.HoverEnd.Value; int daysToHighlight = DateTimeHelper.CompareDays(owner.HoverEnd.Value, owner.HoverStart.Value); if (daysToHighlight < 0) { hEnd = owner.HoverStart.Value; } else { hStart = owner.HoverStart.Value; } int count = ROWS * COLS; for (int childIndex = COLS; childIndex < count; childIndex++) { CalendarDayButton childButton = _monthView.Children[childIndex] as CalendarDayButton; if (childButton.DataContext is DateTime) { DateTime date = (DateTime)childButton.DataContext; childButton.SetValue( CalendarDayButton.IsHighlightedPropertyKey, (daysToHighlight != 0) && DateTimeHelper.InRange(date, hStart, hEnd)); } else { childButton.SetValue(CalendarDayButton.IsHighlightedPropertyKey, false); } } } else { int count = ROWS * COLS; for (int childIndex = COLS; childIndex < count; childIndex++) { CalendarDayButton childButton = _monthView.Children[childIndex] as CalendarDayButton; childButton.SetValue(CalendarDayButton.IsHighlightedPropertyKey, false); } } } private void SetMonthModeHeaderButton() { if (this._headerButton != null) { this._headerButton.Content = DateTimeHelper.ToYearMonthPatternString(DisplayDate, DateTimeHelper.GetCulture(this)); if (this.Owner != null) { this._headerButton.IsEnabled = true; } } } private void SetMonthModeNextButton() { if (this.Owner != null && _nextButton != null) { DateTime firstDayOfMonth = DateTimeHelper.DiscardDayTime(DisplayDate); // DisplayDate is equal to DateTime.MaxValue if (DateTimeHelper.CompareYearMonth(firstDayOfMonth, DateTime.MaxValue) == 0) { _nextButton.IsEnabled = false; } else { // Since we are sure DisplayDate is not equal to DateTime.MaxValue, // it is safe to use AddMonths DateTime firstDayOfNextMonth = _calendar.AddMonths(firstDayOfMonth, 1); _nextButton.IsEnabled = (DateTimeHelper.CompareDays(this.Owner.DisplayDateEndInternal, firstDayOfNextMonth) > -1); } } } private void SetMonthModePreviousButton() { if (this.Owner != null && _previousButton != null) { DateTime firstDayOfMonth = DateTimeHelper.DiscardDayTime(DisplayDate); _previousButton.IsEnabled = (DateTimeHelper.CompareDays(this.Owner.DisplayDateStartInternal, firstDayOfMonth) < 0); } } #endregion #region Year Mode Display private void SetYearButtons(int decade, int decadeEnd) { int year; int count = -1; foreach (object child in _yearView.Children) { CalendarButton childButton = child as CalendarButton; Debug.Assert(childButton != null); year = decade + count; if (year <= DateTime.MaxValue.Year && year >= DateTime.MinValue.Year) { // There should be no time component. Time is 12:00 AM DateTime day = new DateTime(year, 1, 1); childButton.DataContext = day; childButton.SetContentInternal(DateTimeHelper.ToYearString(day, DateTimeHelper.GetCulture(this))); childButton.Visibility = Visibility.Visible; if (this.Owner != null) { childButton.HasSelectedDays = (Owner.DisplayDate.Year == year); if (year < this.Owner.DisplayDateStartInternal.Year || year > this.Owner.DisplayDateEndInternal.Year) { childButton.IsEnabled = false; childButton.Opacity = 0; } else { childButton.IsEnabled = true; childButton.Opacity = 1; } } // SET IF THE YEAR IS INACTIVE OR NOT: set if the year is a trailing year or not childButton.IsInactive = year < decade || year > decadeEnd; } else { childButton.DataContext = null; childButton.IsEnabled = false; childButton.Opacity = 0; } count++; } } private void SetYearModeMonthButtons() { int count = 0; foreach (object child in _yearView.Children) { CalendarButton childButton = child as CalendarButton; Debug.Assert(childButton != null); // There should be no time component. Time is 12:00 AM DateTime day = new DateTime(DisplayDate.Year, count + 1, 1); childButton.DataContext = day; childButton.SetContentInternal(DateTimeHelper.ToAbbreviatedMonthString(day, DateTimeHelper.GetCulture(this))); childButton.Visibility = Visibility.Visible; if (this.Owner != null) { Debug.Assert(this.Owner.DisplayDateInternal != null); childButton.HasSelectedDays = (DateTimeHelper.CompareYearMonth(day, this.Owner.DisplayDateInternal) == 0); if (DateTimeHelper.CompareYearMonth(day, this.Owner.DisplayDateStartInternal) < 0 || DateTimeHelper.CompareYearMonth(day, this.Owner.DisplayDateEndInternal) > 0) { childButton.IsEnabled = false; childButton.Opacity = 0; } else { childButton.IsEnabled = true; childButton.Opacity = 1; } } childButton.IsInactive = false; count++; } } private void SetYearModeHeaderButton() { if (this._headerButton != null) { this._headerButton.IsEnabled = true; this._headerButton.Content = DateTimeHelper.ToYearString(DisplayDate, DateTimeHelper.GetCulture(this)); } } private void SetYearModeNextButton() { if (this.Owner != null && _nextButton != null) { _nextButton.IsEnabled = (this.Owner.DisplayDateEndInternal.Year != DisplayDate.Year); } } private void SetYearModePreviousButton() { if (this.Owner != null && _previousButton != null) { _previousButton.IsEnabled = (this.Owner.DisplayDateStartInternal.Year != DisplayDate.Year); } } #endregion Year Mode Display #region Decade Mode Display private void SetDecadeModeHeaderButton(int decade) { if (this._headerButton != null) { this._headerButton.Content = DateTimeHelper.ToDecadeRangeString(decade, this); this._headerButton.IsEnabled = false; } } private void SetDecadeModeNextButton(int decadeEnd) { if (this.Owner != null && _nextButton != null) { _nextButton.IsEnabled = (this.Owner.DisplayDateEndInternal.Year > decadeEnd); } } private void SetDecadeModePreviousButton(int decade) { if (this.Owner != null && _previousButton != null) { _previousButton.IsEnabled = (decade > this.Owner.DisplayDateStartInternal.Year); } } #endregion Decade Mode Display // How many days of the previous month need to be displayed private int GetNumberOfDisplayedDaysFromPreviousMonth(DateTime firstOfMonth) { DayOfWeek day = _calendar.GetDayOfWeek(firstOfMonth); int i; if (this.Owner != null) { i = ((day - this.Owner.FirstDayOfWeek + NUMBER_OF_DAYS_IN_WEEK) % NUMBER_OF_DAYS_IN_WEEK); } else { i = ((day - DateTimeHelper.GetDateFormat(DateTimeHelper.GetCulture(this)).FirstDayOfWeek + NUMBER_OF_DAYS_IN_WEEK) % NUMBER_OF_DAYS_IN_WEEK); } if (i == 0) { return NUMBER_OF_DAYS_IN_WEEK; } else { return i; } } /// /// Gets a binding to a property on the owning calendar /// /// ///private BindingBase GetOwnerBinding(string propertyName) { Binding result = new Binding(propertyName); result.Source = this.Owner; return result; } #endregion Private Methods #region Resource Keys /// /// Resource key for DayTitleTemplate /// public static ComponentResourceKey DayTitleTemplateResourceKey { get { if (_dayTitleTemplateResourceKey == null) { _dayTitleTemplateResourceKey = new ComponentResourceKey(typeof(CalendarItem), ElementDayTitleTemplate); } return _dayTitleTemplateResourceKey; } } #endregion } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved. //---------------------------------------------------------------------------- // // Copyright (C) Microsoft Corporation. All rights reserved. // //--------------------------------------------------------------------------- using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Input; namespace System.Windows.Controls.Primitives { [TemplatePart(Name = CalendarItem.ElementRoot, Type = typeof(FrameworkElement))] [TemplatePart(Name = CalendarItem.ElementHeaderButton, Type = typeof(Button))] [TemplatePart(Name = CalendarItem.ElementPreviousButton, Type = typeof(Button))] [TemplatePart(Name = CalendarItem.ElementNextButton, Type = typeof(Button))] [TemplatePart(Name = CalendarItem.ElementDayTitleTemplate, Type = typeof(DataTemplate))] [TemplatePart(Name = CalendarItem.ElementMonthView, Type = typeof(Grid))] [TemplatePart(Name = CalendarItem.ElementYearView, Type = typeof(Grid))] [TemplatePart(Name = CalendarItem.ElementDisabledVisual, Type = typeof(FrameworkElement))] public sealed partial class CalendarItem : Control { #region Constants private const string ElementRoot = "PART_Root"; private const string ElementHeaderButton = "PART_HeaderButton"; private const string ElementPreviousButton = "PART_PreviousButton"; private const string ElementNextButton = "PART_NextButton"; private const string ElementDayTitleTemplate = "DayTitleTemplate"; private const string ElementMonthView = "PART_MonthView"; private const string ElementYearView = "PART_YearView"; private const string ElementDisabledVisual = "PART_DisabledVisual"; private const int COLS = 7; private const int ROWS = 7; private const int YEAR_COLS = 4; private const int YEAR_ROWS = 3; private const int NUMBER_OF_DAYS_IN_WEEK = 7; #endregion Constants #region Data private static ComponentResourceKey _dayTitleTemplateResourceKey = null; private System.Globalization.Calendar _calendar = new GregorianCalendar(); private DataTemplate _dayTitleTemplate; private FrameworkElement _disabledVisual; private Button _headerButton; private Grid _monthView; private Button _nextButton; private Button _previousButton; private Grid _yearView; private bool _isMonthPressed; private bool _isDayPressed; #endregion Data static CalendarItem() { DefaultStyleKeyProperty.OverrideMetadata(typeof(CalendarItem), new FrameworkPropertyMetadata(typeof(CalendarItem))); FocusableProperty.OverrideMetadata(typeof(CalendarItem), new FrameworkPropertyMetadata(false)); KeyboardNavigation.TabNavigationProperty.OverrideMetadata(typeof(CalendarItem), new FrameworkPropertyMetadata(KeyboardNavigationMode.Once)); KeyboardNavigation.DirectionalNavigationProperty.OverrideMetadata(typeof(CalendarItem), new FrameworkPropertyMetadata(KeyboardNavigationMode.Contained)); IsEnabledProperty.OverrideMetadata(typeof(CalendarItem), new UIPropertyMetadata(new PropertyChangedCallback(OnVisualStatePropertyChanged))); } ////// Represents the month that is used in Calendar Control. /// public CalendarItem() { } #region Internal Properties internal Grid MonthView { get { return _monthView; } } internal Calendar Owner { get; set; } internal Grid YearView { get { return _yearView; } } #endregion Internal Properties #region Private Properties ////// Gets a value indicating whether the calendar is displayed in months, years or decades. /// private CalendarMode DisplayMode { get { return (this.Owner != null) ? this.Owner.DisplayMode : CalendarMode.Month; } } internal Button HeaderButton { get { return this._headerButton; } } internal Button NextButton { get { return this._nextButton; } } internal Button PreviousButton { get { return this._previousButton; } } private DateTime DisplayDate { get { return (Owner != null) ? Owner.DisplayDate : DateTime.Today; } } #endregion Private Properties #region Public Methods ////// Invoked whenever application code or an internal process, /// such as a rebuilding layout pass, calls the ApplyTemplate method. /// public override void OnApplyTemplate() { base.OnApplyTemplate(); if (this._previousButton != null) { this._previousButton.Click -= new RoutedEventHandler(PreviousButton_Click); } if (this._nextButton != null) { this._nextButton.Click -= new RoutedEventHandler(NextButton_Click); } if (this._headerButton != null) { this._headerButton.Click -= new RoutedEventHandler(HeaderButton_Click); } _monthView = GetTemplateChild(ElementMonthView) as Grid; _yearView = GetTemplateChild(ElementYearView) as Grid; _previousButton = GetTemplateChild(ElementPreviousButton) as Button; _nextButton = GetTemplateChild(ElementNextButton) as Button; _headerButton = GetTemplateChild(ElementHeaderButton) as Button; _disabledVisual = GetTemplateChild(ElementDisabledVisual) as FrameworkElement; // WPF Compat: Unlike SL, WPF is not able to get elements in template resources with GetTemplateChild() _dayTitleTemplate = null; if (Template != null && Template.Resources.Contains(DayTitleTemplateResourceKey)) { _dayTitleTemplate = Template.Resources[DayTitleTemplateResourceKey] as DataTemplate; } if (this._previousButton != null) { // If the user does not provide a Content value in template, we provide a helper text that can be used in Accessibility // this text is not shown on the UI, just used for Accessibility purposes if (this._previousButton.Content == null) { this._previousButton.Content = SR.Get(SRID.Calendar_PreviousButtonName); } this._previousButton.Click += new RoutedEventHandler(PreviousButton_Click); } if (this._nextButton != null) { // If the user does not provide a Content value in template, we provide a helper text that can be used in Accessibility // this text is not shown on the UI, just used for Accessibility purposes if (this._nextButton.Content == null) { this._nextButton.Content = SR.Get(SRID.Calendar_NextButtonName); } this._nextButton.Click += new RoutedEventHandler(NextButton_Click); } if (this._headerButton != null) { this._headerButton.Click += new RoutedEventHandler(HeaderButton_Click); } PopulateGrids(); if (this.Owner != null) { switch (this.Owner.DisplayMode) { case CalendarMode.Year: UpdateYearMode(); break; case CalendarMode.Decade: UpdateDecadeMode(); break; case CalendarMode.Month: UpdateMonthMode(); break; default: Debug.Assert(false); break; } } else { UpdateMonthMode(); } } #endregion Public Methods #region Protected Methods internal override void ChangeVisualState(bool useTransitions) { if (!IsEnabled) { VisualStateManager.GoToState(this, VisualStates.StateDisabled, useTransitions); } else { VisualStateManager.GoToState(this, VisualStates.StateNormal, useTransitions); } base.ChangeVisualState(useTransitions); } protected override void OnMouseUp(MouseButtonEventArgs e) { base.OnMouseUp(e); if (this.IsMouseCaptured) { this.ReleaseMouseCapture(); } this._isMonthPressed = false; this._isDayPressed = false; // In Month mode, we may need to end a drag selection even if the mouse up isn't on the calendar. if (!e.Handled && this.Owner.DisplayMode == CalendarMode.Month && this.Owner.HoverEnd.HasValue) { FinishSelection(this.Owner.HoverEnd.Value); } } protected override void OnLostMouseCapture(MouseEventArgs e) { base.OnLostMouseCapture(e); if (!this.IsMouseCaptured) { this._isDayPressed = false; this._isMonthPressed = false; } } #endregion #region Internal Methods internal void UpdateDecadeMode() { DateTime selectedYear; if (this.Owner != null) { selectedYear = this.Owner.DisplayYear; } else { selectedYear = DateTime.Today; } int decade = GetDecadeForDecadeMode(selectedYear); int decadeEnd = decade + 9; SetDecadeModeHeaderButton(decade); SetDecadeModePreviousButton(decade); SetDecadeModeNextButton(decadeEnd); if (_yearView != null) { SetYearButtons(decade, decadeEnd); } } internal void UpdateMonthMode() { SetMonthModeHeaderButton(); SetMonthModePreviousButton(); SetMonthModeNextButton(); if (_monthView != null) { SetMonthModeDayTitles(); SetMonthModeCalendarDayButtons(); AddMonthModeHighlight(); } } internal void UpdateYearMode() { SetYearModeHeaderButton(); SetYearModePreviousButton(); SetYearModeNextButton(); if (_yearView != null) { SetYearModeMonthButtons(); } } internal IEnumerableGetCalendarDayButtons() { // int count = ROWS * COLS; if (MonthView != null) { UIElementCollection dayButtonsHost = MonthView.Children; for (int childIndex = COLS; childIndex < count; childIndex++) { CalendarDayButton b = dayButtonsHost[childIndex] as CalendarDayButton; if (b != null) { yield return b; } } } } internal CalendarDayButton GetFocusedCalendarDayButton() { foreach (CalendarDayButton b in GetCalendarDayButtons()) { if (b != null && b.IsFocused) { return b; } } return null; } internal CalendarDayButton GetCalendarDayButton(DateTime date) { foreach (CalendarDayButton b in GetCalendarDayButtons()) { if (b != null && b.DataContext is DateTime) { if (DateTimeHelper.CompareDays(date, (DateTime)b.DataContext) == 0) { return b; } } } return null; } internal CalendarButton GetCalendarButton(DateTime date, CalendarMode mode) { Debug.Assert(mode != CalendarMode.Month); foreach (CalendarButton b in GetCalendarButtons()) { if (b != null && b.DataContext is DateTime) { if (mode == CalendarMode.Year) { if (DateTimeHelper.CompareYearMonth(date, (DateTime)b.DataContext) == 0) { return b; } } else { if (date.Year == ((DateTime)b.DataContext).Year) { return b; } } } } return null; } internal CalendarButton GetFocusedCalendarButton() { foreach (CalendarButton b in GetCalendarButtons()) { if (b != null && b.IsFocused) { return b; } } return null; } private IEnumerable GetCalendarButtons() { foreach (UIElement element in this.YearView.Children) { CalendarButton b = element as CalendarButton; if (b != null) { yield return b; } } } internal void FocusDate(DateTime date) { FrameworkElement focusTarget = null; switch (this.DisplayMode) { case CalendarMode.Month: { focusTarget = GetCalendarDayButton(date); break; } case CalendarMode.Year: case CalendarMode.Decade: { focusTarget = GetCalendarButton(date, this.DisplayMode); break; } default: { Debug.Assert(false); break; } } if (focusTarget != null && !focusTarget.IsFocused) { focusTarget.MoveFocus(new TraversalRequest(FocusNavigationDirection.First)); } } #endregion Internal Methods #region Private Methods private int GetDecadeForDecadeMode(DateTime selectedYear) { int decade = DateTimeHelper.DecadeOfDate(selectedYear); // Adjust the decade value if the mouse move selection is on, // such that if first or last year among the children are selected // then return the current selected decade as is. if (_isMonthPressed && _yearView != null) { UIElementCollection yearViewChildren = _yearView.Children; int count = yearViewChildren.Count; if (count > 0) { CalendarButton child = yearViewChildren[0] as CalendarButton; if (child != null && child.DataContext is DateTime && ((DateTime)child.DataContext).Year == selectedYear.Year) { return (decade + 10); } } if (count > 1) { CalendarButton child = yearViewChildren[count - 1] as CalendarButton; if (child != null && child.DataContext is DateTime && ((DateTime)child.DataContext).Year == selectedYear.Year) { return (decade - 10); } } } return decade; } private void EndDrag(bool ctrl, DateTime selectedDate) { if (this.Owner != null) { this.Owner.CurrentDate = selectedDate; if (this.Owner.HoverStart.HasValue) { if ( ctrl && DateTime.Compare(this.Owner.HoverStart.Value, selectedDate) == 0 && (Owner.SelectionMode == CalendarSelectionMode.SingleDate || Owner.SelectionMode == CalendarSelectionMode.MultipleRange)) { // Ctrl + single click = toggle this.Owner.SelectedDates.Toggle(selectedDate); } else { // this is selection with Mouse, we do not guarantee the range does not include BlackOutDates. // Use the internal AddRange that omits BlackOutDates based on the SelectionMode this.Owner.SelectedDates.AddRangeInternal(this.Owner.HoverStart.Value, selectedDate); } Owner.OnDayClick(selectedDate); } } } private void CellOrMonth_PreviewKeyDown(object sender, RoutedEventArgs e) { Debug.Assert(e != null); if (this.Owner == null) { return; } this.Owner.OnDayOrMonthPreviewKeyDown(e); } private void Cell_Clicked(object sender, RoutedEventArgs e) { if (this.Owner == null) { return; } CalendarDayButton b = sender as CalendarDayButton; Debug.Assert(b != null); if (!(b.DataContext is DateTime)) { return; } // If the day is a blackout day selection is not allowed if (!b.IsBlackedOut) { DateTime clickedDate = (DateTime)b.DataContext; bool ctrl, shift; CalendarKeyboardHelper.GetMetaKeyState(out ctrl, out shift); switch (this.Owner.SelectionMode) { case CalendarSelectionMode.None: { break; } case CalendarSelectionMode.SingleDate: { if (!ctrl) { this.Owner.SelectedDate = clickedDate; } else { this.Owner.SelectedDates.Toggle(clickedDate); } break; } case CalendarSelectionMode.SingleRange: { DateTime? lastDate = this.Owner.CurrentDate; this.Owner.SelectedDates.ClearInternal(true /*fireChangeNotification*/); if (shift && lastDate.HasValue) { this.Owner.SelectedDates.AddRangeInternal(lastDate.Value, clickedDate); } else { this.Owner.SelectedDate = clickedDate; this.Owner.HoverStart = null; this.Owner.HoverEnd = null; } break; } case CalendarSelectionMode.MultipleRange: { if (!ctrl) { this.Owner.SelectedDates.ClearInternal(true /*fireChangeNotification*/); } if (shift) { this.Owner.SelectedDates.AddRangeInternal(this.Owner.CurrentDate, clickedDate); } else { if (!ctrl) { this.Owner.SelectedDate = clickedDate; } else { this.Owner.SelectedDates.Toggle(clickedDate); this.Owner.HoverStart = null; this.Owner.HoverEnd = null; } } break; } } this.Owner.OnDayClick(clickedDate); } } private void Cell_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { CalendarDayButton b = sender as CalendarDayButton; if (b == null) { return; } if (this.Owner == null || !(b.DataContext is DateTime)) { return; } if (b.IsBlackedOut) { this.Owner.HoverStart = null; } else { this._isDayPressed = true; Mouse.Capture(this, CaptureMode.SubTree); b.MoveFocus(new TraversalRequest(FocusNavigationDirection.First)); bool ctrl, shift; CalendarKeyboardHelper.GetMetaKeyState(out ctrl, out shift); DateTime selectedDate = (DateTime)b.DataContext; Debug.Assert(selectedDate != null); switch (this.Owner.SelectionMode) { case CalendarSelectionMode.None: { break; } case CalendarSelectionMode.SingleDate: { this.Owner.DatePickerDisplayDateFlag = true; if (!ctrl) { this.Owner.SelectedDate = selectedDate; } else { this.Owner.SelectedDates.Toggle(selectedDate); } break; } case CalendarSelectionMode.SingleRange: { this.Owner.SelectedDates.ClearInternal(); if (shift) { if (!this.Owner.HoverStart.HasValue) { this.Owner.HoverStart = this.Owner.HoverEnd = this.Owner.CurrentDate; } } else { this.Owner.HoverStart = this.Owner.HoverEnd = selectedDate; } break; } case CalendarSelectionMode.MultipleRange: { if (!ctrl) { this.Owner.SelectedDates.ClearInternal(); } if (shift) { if (!this.Owner.HoverStart.HasValue) { this.Owner.HoverStart = this.Owner.HoverEnd = this.Owner.CurrentDate; } } else { this.Owner.HoverStart = this.Owner.HoverEnd = selectedDate; } break; } } this.Owner.CurrentDate = selectedDate; this.Owner.UpdateCellItems(); } } private void Cell_MouseEnter(object sender, MouseEventArgs e) { CalendarDayButton b = sender as CalendarDayButton; if (b == null) { return; } if (b.IsBlackedOut) { return; } if (e.LeftButton == MouseButtonState.Pressed && this._isDayPressed) { b.MoveFocus(new TraversalRequest(FocusNavigationDirection.First)); if (this.Owner == null || !(b.DataContext is DateTime)) { return; } DateTime selectedDate = (DateTime)b.DataContext; switch (this.Owner.SelectionMode) { case CalendarSelectionMode.SingleDate: { this.Owner.DatePickerDisplayDateFlag = true; this.Owner.HoverStart = this.Owner.HoverEnd = null; if (this.Owner.SelectedDates.Count == 0) { this.Owner.SelectedDates.Add(selectedDate); } else { this.Owner.SelectedDates[0] = selectedDate; } return; } } this.Owner.HoverEnd = selectedDate; this.Owner.CurrentDate = selectedDate; this.Owner.UpdateCellItems(); } } private void Cell_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) { CalendarDayButton b = sender as CalendarDayButton; if (b == null) { return; } if (this.Owner == null) { return; } if (!b.IsBlackedOut) { this.Owner.OnDayButtonMouseUp(e); } if (!(b.DataContext is DateTime)) { return; } FinishSelection((DateTime)b.DataContext); e.Handled = true; } private void FinishSelection(DateTime selectedDate) { bool ctrl, shift; CalendarKeyboardHelper.GetMetaKeyState(out ctrl, out shift); if (this.Owner.SelectionMode == CalendarSelectionMode.None || this.Owner.SelectionMode == CalendarSelectionMode.SingleDate) { this.Owner.OnDayClick(selectedDate); return; } if (this.Owner.HoverStart.HasValue) { switch (this.Owner.SelectionMode) { case CalendarSelectionMode.SingleRange: { // Update SelectedDates this.Owner.SelectedDates.ClearInternal(); EndDrag(ctrl, selectedDate); break; } case CalendarSelectionMode.MultipleRange: { // add the selection (either single day or SingleRange day) EndDrag(ctrl, selectedDate); break; } } } else { // If the day is blacked out but also a trailing day we should be able to switch months CalendarDayButton b = GetCalendarDayButton(selectedDate); if (b != null && b.IsInactive && b.IsBlackedOut) { this.Owner.OnDayClick(selectedDate); } } } private void Month_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { CalendarButton b = sender as CalendarButton; if (b != null) { this._isMonthPressed = true; Mouse.Capture(this, CaptureMode.SubTree); if (this.Owner != null) { this.Owner.OnCalendarButtonPressed(b, false); } } } private void Month_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) { CalendarButton b = sender as CalendarButton; if (b != null && this.Owner != null) { this.Owner.OnCalendarButtonPressed(b, true); } } private void Month_MouseEnter(object sender, MouseEventArgs e) { CalendarButton b = sender as CalendarButton; if (b != null) { if (this._isMonthPressed && this.Owner != null) { this.Owner.OnCalendarButtonPressed(b, false); } } } private void Month_Clicked(object sender, RoutedEventArgs e) { CalendarButton b = sender as CalendarButton; if (b != null) { this.Owner.OnCalendarButtonPressed(b, true); } } private void HeaderButton_Click(object sender, RoutedEventArgs e) { if (this.Owner != null) { if (this.Owner.DisplayMode == CalendarMode.Month) { this.Owner.SetCurrentValueInternal(Calendar.DisplayModeProperty, CalendarMode.Year); } else { Debug.Assert(this.Owner.DisplayMode == CalendarMode.Year); this.Owner.SetCurrentValueInternal(Calendar.DisplayModeProperty, CalendarMode.Decade); } this.FocusDate(this.DisplayDate); } } private void PreviousButton_Click(object sender, RoutedEventArgs e) { if (this.Owner != null) { this.Owner.OnPreviousClick(); } } private void NextButton_Click(object sender, RoutedEventArgs e) { if (this.Owner != null) { this.Owner.OnNextClick(); } } private void PopulateGrids() { if (_monthView != null) { for (int i = 0; i < COLS; i++) { FrameworkElement titleCell = (this._dayTitleTemplate != null) ? (FrameworkElement)this._dayTitleTemplate.LoadContent() : new ContentControl(); titleCell.SetValue(Grid.RowProperty, 0); titleCell.SetValue(Grid.ColumnProperty, i); this._monthView.Children.Add(titleCell); } for (int i = 1; i < ROWS; i++) { for (int j = 0; j < COLS; j++) { CalendarDayButton dayCell = new CalendarDayButton(); dayCell.Owner = this.Owner; dayCell.SetValue(Grid.RowProperty, i); dayCell.SetValue(Grid.ColumnProperty, j); dayCell.SetBinding(CalendarDayButton.StyleProperty, GetOwnerBinding("CalendarDayButtonStyle")); dayCell.AddHandler(CalendarDayButton.MouseLeftButtonDownEvent, new MouseButtonEventHandler(Cell_MouseLeftButtonDown), true); dayCell.AddHandler(CalendarDayButton.MouseLeftButtonUpEvent, new MouseButtonEventHandler(Cell_MouseLeftButtonUp), true); dayCell.AddHandler(CalendarDayButton.MouseEnterEvent, new MouseEventHandler(Cell_MouseEnter), true); dayCell.Click += new RoutedEventHandler(Cell_Clicked); dayCell.AddHandler(PreviewKeyDownEvent, new RoutedEventHandler(CellOrMonth_PreviewKeyDown), true); this._monthView.Children.Add(dayCell); } } } if (_yearView != null) { CalendarButton monthCell; int count = 0; for (int i = 0; i < YEAR_ROWS; i++) { for (int j = 0; j < YEAR_COLS; j++) { monthCell = new CalendarButton(); monthCell.Owner = this.Owner; monthCell.SetValue(Grid.RowProperty, i); monthCell.SetValue(Grid.ColumnProperty, j); monthCell.SetBinding(CalendarButton.StyleProperty, GetOwnerBinding("CalendarButtonStyle")); monthCell.AddHandler(CalendarButton.MouseLeftButtonDownEvent, new MouseButtonEventHandler(Month_MouseLeftButtonDown), true); monthCell.AddHandler(CalendarButton.MouseLeftButtonUpEvent, new MouseButtonEventHandler(Month_MouseLeftButtonUp), true); monthCell.AddHandler(CalendarButton.MouseEnterEvent, new MouseEventHandler(Month_MouseEnter), true); monthCell.AddHandler(UIElement.PreviewKeyDownEvent, new RoutedEventHandler(CellOrMonth_PreviewKeyDown), true); monthCell.Click += new RoutedEventHandler(Month_Clicked); this._yearView.Children.Add(monthCell); count++; } } } } #region Month Mode Display private void SetMonthModeDayTitles() { if (_monthView != null) { string[] shortestDayNames = DateTimeHelper.GetDateFormat(DateTimeHelper.GetCulture(this)).ShortestDayNames; for (int childIndex = 0; childIndex < COLS; childIndex++) { FrameworkElement daytitle = _monthView.Children[childIndex] as FrameworkElement; if (daytitle != null && shortestDayNames != null && shortestDayNames.Length > 0) { if (this.Owner != null) { daytitle.DataContext = shortestDayNames[(childIndex + (int)this.Owner.FirstDayOfWeek) % shortestDayNames.Length]; } else { daytitle.DataContext = shortestDayNames[(childIndex + (int)DateTimeHelper.GetDateFormat( DateTimeHelper.GetCulture(this)).FirstDayOfWeek) % shortestDayNames.Length]; } } } } } private void SetMonthModeCalendarDayButtons() { DateTime firstDayOfMonth = DateTimeHelper.DiscardDayTime(DisplayDate); int lastMonthToDisplay = GetNumberOfDisplayedDaysFromPreviousMonth(firstDayOfMonth); bool isMinMonth = DateTimeHelper.CompareYearMonth(firstDayOfMonth, DateTime.MinValue) <= 0; bool isMaxMonth = DateTimeHelper.CompareYearMonth(firstDayOfMonth, DateTime.MaxValue) >= 0; int daysInMonth = _calendar.GetDaysInMonth(firstDayOfMonth.Year, firstDayOfMonth.Month); CultureInfo culture = DateTimeHelper.GetCulture(this); int count = ROWS * COLS; for (int childIndex = COLS; childIndex < count; childIndex++) { CalendarDayButton childButton = _monthView.Children[childIndex] as CalendarDayButton; Debug.Assert(childButton != null); int dayOffset = childIndex - lastMonthToDisplay - COLS; if ((!isMinMonth || (dayOffset >= 0)) && (!isMaxMonth || (dayOffset < daysInMonth))) { DateTime dateToAdd = _calendar.AddDays(firstDayOfMonth, dayOffset); SetMonthModeDayButtonState(childButton, dateToAdd); childButton.DataContext = dateToAdd; childButton.SetContentInternal(DateTimeHelper.ToDayString(dateToAdd, culture)); } else { SetMonthModeDayButtonState(childButton, null); childButton.DataContext = null; childButton.SetContentInternal(DateTimeHelper.ToDayString(null, culture)); } } } private void SetMonthModeDayButtonState(CalendarDayButton childButton, DateTime? dateToAdd) { if (this.Owner != null) { if (dateToAdd.HasValue) { childButton.Visibility = Visibility.Visible; // If the day is outside the DisplayDateStart/End boundary, do not show it if (DateTimeHelper.CompareDays(dateToAdd.Value, this.Owner.DisplayDateStartInternal) < 0 || DateTimeHelper.CompareDays(dateToAdd.Value, this.Owner.DisplayDateEndInternal) > 0) { childButton.IsEnabled = false; childButton.Visibility = Visibility.Hidden; } else { childButton.IsEnabled = true; // SET IF THE DAY IS SELECTABLE OR NOT childButton.SetValue( CalendarDayButton.IsBlackedOutPropertyKey, this.Owner.BlackoutDates.Contains(dateToAdd.Value)); // SET IF THE DAY IS ACTIVE OR NOT: set if the day is a trailing day or not childButton.SetValue( CalendarDayButton.IsInactivePropertyKey, DateTimeHelper.CompareYearMonth(dateToAdd.Value, this.Owner.DisplayDateInternal) != 0); // SET IF THE DAY IS TODAY OR NOT if (DateTimeHelper.CompareDays(dateToAdd.Value, DateTime.Today) == 0) { childButton.SetValue(CalendarDayButton.IsTodayPropertyKey, true); } else { childButton.SetValue(CalendarDayButton.IsTodayPropertyKey, false); } // the child button doesn't get change notificaitons from Calendar.IsTodayHighlighted // so we need up change visual states to ensure the IsToday is up to date. childButton.NotifyNeedsVisualStateUpdate(); // SET IF THE DAY IS SELECTED OR NOT // Since we should be comparing the Date values not DateTime values, we can't use this.Owner.SelectedDates.Contains(dateToAdd) directly bool isSelected = false; foreach (DateTime item in this.Owner.SelectedDates) { isSelected |= (DateTimeHelper.CompareDays(dateToAdd.Value, item) == 0); } childButton.SetValue(CalendarDayButton.IsSelectedPropertyKey, isSelected); } } else { childButton.Visibility = Visibility.Hidden; childButton.IsEnabled = false; childButton.SetValue(CalendarDayButton.IsBlackedOutPropertyKey, false); childButton.SetValue(CalendarDayButton.IsInactivePropertyKey, true); childButton.SetValue(CalendarDayButton.IsTodayPropertyKey, false); childButton.SetValue(CalendarDayButton.IsSelectedPropertyKey, false); } } } private void AddMonthModeHighlight() { var owner = this.Owner; if (owner == null) { return; } if (owner.HoverStart.HasValue && owner.HoverEnd.HasValue) { DateTime hStart = owner.HoverEnd.Value; DateTime hEnd = owner.HoverEnd.Value; int daysToHighlight = DateTimeHelper.CompareDays(owner.HoverEnd.Value, owner.HoverStart.Value); if (daysToHighlight < 0) { hEnd = owner.HoverStart.Value; } else { hStart = owner.HoverStart.Value; } int count = ROWS * COLS; for (int childIndex = COLS; childIndex < count; childIndex++) { CalendarDayButton childButton = _monthView.Children[childIndex] as CalendarDayButton; if (childButton.DataContext is DateTime) { DateTime date = (DateTime)childButton.DataContext; childButton.SetValue( CalendarDayButton.IsHighlightedPropertyKey, (daysToHighlight != 0) && DateTimeHelper.InRange(date, hStart, hEnd)); } else { childButton.SetValue(CalendarDayButton.IsHighlightedPropertyKey, false); } } } else { int count = ROWS * COLS; for (int childIndex = COLS; childIndex < count; childIndex++) { CalendarDayButton childButton = _monthView.Children[childIndex] as CalendarDayButton; childButton.SetValue(CalendarDayButton.IsHighlightedPropertyKey, false); } } } private void SetMonthModeHeaderButton() { if (this._headerButton != null) { this._headerButton.Content = DateTimeHelper.ToYearMonthPatternString(DisplayDate, DateTimeHelper.GetCulture(this)); if (this.Owner != null) { this._headerButton.IsEnabled = true; } } } private void SetMonthModeNextButton() { if (this.Owner != null && _nextButton != null) { DateTime firstDayOfMonth = DateTimeHelper.DiscardDayTime(DisplayDate); // DisplayDate is equal to DateTime.MaxValue if (DateTimeHelper.CompareYearMonth(firstDayOfMonth, DateTime.MaxValue) == 0) { _nextButton.IsEnabled = false; } else { // Since we are sure DisplayDate is not equal to DateTime.MaxValue, // it is safe to use AddMonths DateTime firstDayOfNextMonth = _calendar.AddMonths(firstDayOfMonth, 1); _nextButton.IsEnabled = (DateTimeHelper.CompareDays(this.Owner.DisplayDateEndInternal, firstDayOfNextMonth) > -1); } } } private void SetMonthModePreviousButton() { if (this.Owner != null && _previousButton != null) { DateTime firstDayOfMonth = DateTimeHelper.DiscardDayTime(DisplayDate); _previousButton.IsEnabled = (DateTimeHelper.CompareDays(this.Owner.DisplayDateStartInternal, firstDayOfMonth) < 0); } } #endregion #region Year Mode Display private void SetYearButtons(int decade, int decadeEnd) { int year; int count = -1; foreach (object child in _yearView.Children) { CalendarButton childButton = child as CalendarButton; Debug.Assert(childButton != null); year = decade + count; if (year <= DateTime.MaxValue.Year && year >= DateTime.MinValue.Year) { // There should be no time component. Time is 12:00 AM DateTime day = new DateTime(year, 1, 1); childButton.DataContext = day; childButton.SetContentInternal(DateTimeHelper.ToYearString(day, DateTimeHelper.GetCulture(this))); childButton.Visibility = Visibility.Visible; if (this.Owner != null) { childButton.HasSelectedDays = (Owner.DisplayDate.Year == year); if (year < this.Owner.DisplayDateStartInternal.Year || year > this.Owner.DisplayDateEndInternal.Year) { childButton.IsEnabled = false; childButton.Opacity = 0; } else { childButton.IsEnabled = true; childButton.Opacity = 1; } } // SET IF THE YEAR IS INACTIVE OR NOT: set if the year is a trailing year or not childButton.IsInactive = year < decade || year > decadeEnd; } else { childButton.DataContext = null; childButton.IsEnabled = false; childButton.Opacity = 0; } count++; } } private void SetYearModeMonthButtons() { int count = 0; foreach (object child in _yearView.Children) { CalendarButton childButton = child as CalendarButton; Debug.Assert(childButton != null); // There should be no time component. Time is 12:00 AM DateTime day = new DateTime(DisplayDate.Year, count + 1, 1); childButton.DataContext = day; childButton.SetContentInternal(DateTimeHelper.ToAbbreviatedMonthString(day, DateTimeHelper.GetCulture(this))); childButton.Visibility = Visibility.Visible; if (this.Owner != null) { Debug.Assert(this.Owner.DisplayDateInternal != null); childButton.HasSelectedDays = (DateTimeHelper.CompareYearMonth(day, this.Owner.DisplayDateInternal) == 0); if (DateTimeHelper.CompareYearMonth(day, this.Owner.DisplayDateStartInternal) < 0 || DateTimeHelper.CompareYearMonth(day, this.Owner.DisplayDateEndInternal) > 0) { childButton.IsEnabled = false; childButton.Opacity = 0; } else { childButton.IsEnabled = true; childButton.Opacity = 1; } } childButton.IsInactive = false; count++; } } private void SetYearModeHeaderButton() { if (this._headerButton != null) { this._headerButton.IsEnabled = true; this._headerButton.Content = DateTimeHelper.ToYearString(DisplayDate, DateTimeHelper.GetCulture(this)); } } private void SetYearModeNextButton() { if (this.Owner != null && _nextButton != null) { _nextButton.IsEnabled = (this.Owner.DisplayDateEndInternal.Year != DisplayDate.Year); } } private void SetYearModePreviousButton() { if (this.Owner != null && _previousButton != null) { _previousButton.IsEnabled = (this.Owner.DisplayDateStartInternal.Year != DisplayDate.Year); } } #endregion Year Mode Display #region Decade Mode Display private void SetDecadeModeHeaderButton(int decade) { if (this._headerButton != null) { this._headerButton.Content = DateTimeHelper.ToDecadeRangeString(decade, this); this._headerButton.IsEnabled = false; } } private void SetDecadeModeNextButton(int decadeEnd) { if (this.Owner != null && _nextButton != null) { _nextButton.IsEnabled = (this.Owner.DisplayDateEndInternal.Year > decadeEnd); } } private void SetDecadeModePreviousButton(int decade) { if (this.Owner != null && _previousButton != null) { _previousButton.IsEnabled = (decade > this.Owner.DisplayDateStartInternal.Year); } } #endregion Decade Mode Display // How many days of the previous month need to be displayed private int GetNumberOfDisplayedDaysFromPreviousMonth(DateTime firstOfMonth) { DayOfWeek day = _calendar.GetDayOfWeek(firstOfMonth); int i; if (this.Owner != null) { i = ((day - this.Owner.FirstDayOfWeek + NUMBER_OF_DAYS_IN_WEEK) % NUMBER_OF_DAYS_IN_WEEK); } else { i = ((day - DateTimeHelper.GetDateFormat(DateTimeHelper.GetCulture(this)).FirstDayOfWeek + NUMBER_OF_DAYS_IN_WEEK) % NUMBER_OF_DAYS_IN_WEEK); } if (i == 0) { return NUMBER_OF_DAYS_IN_WEEK; } else { return i; } } /// /// Gets a binding to a property on the owning calendar /// /// ///private BindingBase GetOwnerBinding(string propertyName) { Binding result = new Binding(propertyName); result.Source = this.Owner; return result; } #endregion Private Methods #region Resource Keys /// /// Resource key for DayTitleTemplate /// public static ComponentResourceKey DayTitleTemplateResourceKey { get { if (_dayTitleTemplateResourceKey == null) { _dayTitleTemplateResourceKey = new ComponentResourceKey(typeof(CalendarItem), ElementDayTitleTemplate); } return _dayTitleTemplateResourceKey; } } #endregion } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- HttpContext.cs
- GZipStream.cs
- TablePattern.cs
- CompilerTypeWithParams.cs
- RegexCompiler.cs
- ComponentCommands.cs
- PropertyIDSet.cs
- Comparer.cs
- PaginationProgressEventArgs.cs
- RSAPKCS1KeyExchangeFormatter.cs
- GeneralTransformGroup.cs
- Compensate.cs
- SecurityDocument.cs
- RelatedPropertyManager.cs
- WebReferenceOptions.cs
- WebUtil.cs
- HttpCapabilitiesSectionHandler.cs
- Monitor.cs
- SecurityDescriptor.cs
- PeerApplicationLaunchInfo.cs
- DotAtomReader.cs
- ToolStripContentPanelRenderEventArgs.cs
- XamlStyleSerializer.cs
- Point3D.cs
- XmlFormatWriterGenerator.cs
- VideoDrawing.cs
- XamlRtfConverter.cs
- SelectionPattern.cs
- PageRequestManager.cs
- PropertyInformation.cs
- TemplateNameScope.cs
- WebHttpDispatchOperationSelector.cs
- Trace.cs
- TransformerInfo.cs
- WorkflowMarkupSerializationManager.cs
- ValueOfAction.cs
- TemplateBindingExpression.cs
- COM2ExtendedTypeConverter.cs
- IPipelineRuntime.cs
- FileDialogCustomPlacesCollection.cs
- RNGCryptoServiceProvider.cs
- RefreshEventArgs.cs
- CachedBitmap.cs
- CapiSymmetricAlgorithm.cs
- StrokeNode.cs
- KeyboardInputProviderAcquireFocusEventArgs.cs
- WebPartVerbCollection.cs
- SessionStateSection.cs
- AssertFilter.cs
- BroadcastEventHelper.cs
- TextElement.cs
- CookielessHelper.cs
- DataGridComboBoxColumn.cs
- WinInet.cs
- DirectoryObjectSecurity.cs
- XmlDataSource.cs
- CommandSet.cs
- TransformedBitmap.cs
- ItemContainerGenerator.cs
- Subtract.cs
- Grid.cs
- DesignerSerializationVisibilityAttribute.cs
- CompilerParameters.cs
- SqlTypeSystemProvider.cs
- MsdtcClusterUtils.cs
- RefreshEventArgs.cs
- ConfigurationValue.cs
- DataBindingHandlerAttribute.cs
- ExceptionUtil.cs
- CodeExporter.cs
- CultureSpecificStringDictionary.cs
- TaiwanCalendar.cs
- MetafileHeaderEmf.cs
- PerfProviderCollection.cs
- CounterCreationDataConverter.cs
- Attachment.cs
- DbParameterCollection.cs
- _TimerThread.cs
- securitycriticaldataClass.cs
- IdnMapping.cs
- ObjectDataSourceView.cs
- __Filters.cs
- StandardCommands.cs
- PenContexts.cs
- messageonlyhwndwrapper.cs
- ProxyWebPart.cs
- HtmlTitle.cs
- DataKeyCollection.cs
- WebColorConverter.cs
- XmlBufferedByteStreamReader.cs
- TypeUtil.cs
- UnmanagedBitmapWrapper.cs
- ParameterInfo.cs
- SymbolMethod.cs
- StringSource.cs
- HtmlControlPersistable.cs
- EntityContainerAssociationSetEnd.cs
- WeakReferenceKey.cs
- TypeResolvingOptions.cs
- Package.cs