| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361 |
- // (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 Avalonia.Threading;
- using System;
- using System.Collections.ObjectModel;
- using System.Threading;
- namespace Avalonia.Controls.Primitives
- {
- public sealed class SelectedDatesCollection : ObservableCollection<DateTime>
- {
- /// <summary>
- /// Inherited code: Requires comment.
- /// </summary>
- private Collection<DateTime> _addedItems;
-
- /// <summary>
- /// Inherited code: Requires comment.
- /// </summary>
- private bool _isCleared;
- /// <summary>
- /// Inherited code: Requires comment.
- /// </summary>
- private bool _isRangeAdded;
- /// <summary>
- /// Inherited code: Requires comment.
- /// </summary>
- private Calendar _owner;
- /// <summary>
- /// Initializes a new instance of the
- /// <see cref="T:Avalonia.Controls.Primitives.SelectedDatesCollection" />
- /// class.
- /// </summary>
- /// <param name="owner">
- /// The <see cref="T:Avalonia.Controls.Calendar" /> associated
- /// with this object.
- /// </param>
- public SelectedDatesCollection(Calendar owner)
- {
- _owner = owner;
- _addedItems = new Collection<DateTime>();
- }
- private void InvokeCollectionChanged(System.Collections.IList removedItems, System.Collections.IList addedItems)
- {
- _owner.OnSelectedDatesCollectionChanged(new SelectionChangedEventArgs(null, addedItems, removedItems));
- }
- /// <summary>
- /// Adds all the dates in the specified range, which includes the first
- /// and last dates, to the collection.
- /// </summary>
- /// <param name="start">The first date to add to the collection.</param>
- /// <param name="end">The last date to add to the collection.</param>
- public void AddRange(DateTime start, DateTime end)
- {
- DateTime? rangeStart;
- // increment parameter specifies if the Days were selected in
- // Descending order or Ascending order based on this value, we add
- // the days in the range either in Ascending order or in Descending
- // order
- int increment = (DateTime.Compare(end, start) >= 0) ? 1 : -1;
- _addedItems.Clear();
- rangeStart = start;
- _isRangeAdded = true;
- if (_owner.IsMouseSelection)
- {
- // In Mouse Selection we allow the user to be able to add
- // multiple ranges in one action in MultipleRange Mode. In
- // SingleRange Mode, we only add the first selected range.
- while (rangeStart.HasValue && DateTime.Compare(end, rangeStart.Value) != -increment)
- {
- if (Calendar.IsValidDateSelection(_owner, rangeStart))
- {
- Add(rangeStart.Value);
- }
- else
- {
- if (_owner.SelectionMode == CalendarSelectionMode.SingleRange)
- {
- _owner.HoverEnd = rangeStart.Value.AddDays(-increment);
- break;
- }
- }
- rangeStart = DateTimeHelper.AddDays(rangeStart.Value, increment);
- }
- }
- else
- {
- // If CalendarSelectionMode.SingleRange and a user
- // programmatically tries to add multiple ranges, we will throw
- // away the old range and replace it with the new one. In order
- // to provide the removed items without an additional event, we
- // are calling ClearInternal
- if (_owner.SelectionMode == CalendarSelectionMode.SingleRange && Count > 0)
- {
- foreach (DateTime item in this)
- {
- _owner.RemovedItems.Add(item);
- }
- ClearInternal();
- }
- while (rangeStart.HasValue && DateTime.Compare(end, rangeStart.Value) != -increment)
- {
- Add(rangeStart.Value);
- rangeStart = DateTimeHelper.AddDays(rangeStart.Value, increment);
- }
- }
- _owner.OnSelectedDatesCollectionChanged(new SelectionChangedEventArgs(null, _addedItems, _owner.RemovedItems));
- _owner.RemovedItems.Clear();
- _owner.UpdateMonths();
- _isRangeAdded = false;
- }
- /// <summary>
- /// Removes all items from the collection.
- /// </summary>
- /// <remarks>
- /// This implementation raises the CollectionChanged event.
- /// </remarks>
- protected override void ClearItems()
- {
- EnsureValidThread();
- Collection<DateTime> addedItems = new Collection<DateTime>();
- Collection<DateTime> removedItems = new Collection<DateTime>();
- foreach (DateTime item in this)
- {
- removedItems.Add(item);
- }
- base.ClearItems();
- // The event fires after SelectedDate changes
- if (_owner.SelectionMode != CalendarSelectionMode.None && _owner.SelectedDate != null)
- {
- _owner.SelectedDate = null;
- }
- if (removedItems.Count != 0)
- {
- InvokeCollectionChanged(removedItems, addedItems);
- }
- _owner.UpdateMonths();
- }
- /// <summary>
- /// Inserts an item into the collection at the specified index.
- /// </summary>
- /// <param name="index">
- /// The zero-based index at which item should be inserted.
- /// </param>
- /// <param name="item">The object to insert.</param>
- /// <remarks>
- /// This implementation raises the CollectionChanged event.
- /// </remarks>
- protected override void InsertItem(int index, DateTime item)
- {
- EnsureValidThread();
- if (!Contains(item))
- {
- Collection<DateTime> addedItems = new Collection<DateTime>();
- if (CheckSelectionMode())
- {
- if (Calendar.IsValidDateSelection(_owner, item))
- {
- // If the Collection is cleared since it is SingleRange
- // and it had another range set the index to 0
- if (_isCleared)
- {
- index = 0;
- _isCleared = false;
- }
- base.InsertItem(index, item);
- // The event fires after SelectedDate changes
- if (index == 0 && !(_owner.SelectedDate.HasValue && DateTime.Compare(_owner.SelectedDate.Value, item) == 0))
- {
- _owner.SelectedDate = item;
- }
- if (!_isRangeAdded)
- {
- addedItems.Add(item);
- InvokeCollectionChanged(_owner.RemovedItems, addedItems);
- _owner.RemovedItems.Clear();
- int monthDifference = DateTimeHelper.CompareYearMonth(item, _owner.DisplayDateInternal);
- if (monthDifference < 2 && monthDifference > -2)
- {
- _owner.UpdateMonths();
- }
- }
- else
- {
- _addedItems.Add(item);
- }
- }
- else
- {
- throw new ArgumentOutOfRangeException("SelectedDate value is not valid.");
- }
- }
- }
- }
- /// <summary>
- /// Removes the item at the specified index of the collection.
- /// </summary>
- /// <param name="index">
- /// The zero-based index of the element to remove.
- /// </param>
- /// <remarks>
- /// This implementation raises the CollectionChanged event.
- /// </remarks>
- protected override void RemoveItem(int index)
- {
- EnsureValidThread();
- if (index >= Count)
- {
- base.RemoveItem(index);
- }
- else
- {
- Collection<DateTime> addedItems = new Collection<DateTime>();
- Collection<DateTime> removedItems = new Collection<DateTime>();
- int monthDifference = DateTimeHelper.CompareYearMonth(this[index], _owner.DisplayDateInternal);
- removedItems.Add(this[index]);
- base.RemoveItem(index);
- // The event fires after SelectedDate changes
- if (index == 0)
- {
- if (Count > 0)
- {
- _owner.SelectedDate = this[0];
- }
- else
- {
- _owner.SelectedDate = null;
- }
- }
- InvokeCollectionChanged(removedItems, addedItems);
- if (monthDifference < 2 && monthDifference > -2)
- {
- _owner.UpdateMonths();
- }
- }
- }
- /// <summary>
- /// Replaces the element at the specified index.
- /// </summary>
- /// <param name="index">
- /// The zero-based index of the element to replace.
- /// </param>
- /// <param name="item">
- /// The new value for the element at the specified index.
- /// </param>
- /// <remarks>
- /// This implementation raises the CollectionChanged event.
- /// </remarks>
- protected override void SetItem(int index, DateTime item)
- {
- EnsureValidThread();
- if (!Contains(item))
- {
- Collection<DateTime> addedItems = new Collection<DateTime>();
- Collection<DateTime> removedItems = new Collection<DateTime>();
- if (index >= Count)
- {
- base.SetItem(index, item);
- }
- else
- {
- if (item != null && DateTime.Compare(this[index], item) != 0 && Calendar.IsValidDateSelection(_owner, item))
- {
- removedItems.Add(this[index]);
- base.SetItem(index, item);
- addedItems.Add(item);
- // The event fires after SelectedDate changes
- if (index == 0 && !(_owner.SelectedDate.HasValue && DateTime.Compare(_owner.SelectedDate.Value, item) == 0))
- {
- _owner.SelectedDate = item;
- }
- InvokeCollectionChanged(removedItems, addedItems);
- int monthDifference = DateTimeHelper.CompareYearMonth(item, _owner.DisplayDateInternal);
- if (monthDifference < 2 && monthDifference > -2)
- {
- _owner.UpdateMonths();
- }
- }
- }
- }
- }
-
- internal void ClearInternal()
- {
- base.ClearItems();
- }
-
- private bool CheckSelectionMode()
- {
- if (_owner.SelectionMode == CalendarSelectionMode.None)
- {
- throw new InvalidOperationException("The SelectedDate property cannot be set when the selection mode is None.");
- }
- if (_owner.SelectionMode == CalendarSelectionMode.SingleDate && Count > 0)
- {
- throw new InvalidOperationException("The SelectedDates collection can be changed only in a multiple selection mode. Use the SelectedDate in a single selection mode.");
- }
- // if user tries to add an item into the SelectedDates in
- // SingleRange mode, we throw away the old range and replace it with
- // the new one in order to provide the removed items without an
- // additional event, we are calling ClearInternal
- if (_owner.SelectionMode == CalendarSelectionMode.SingleRange && !_isRangeAdded && Count > 0)
- {
- foreach (DateTime item in this)
- {
- _owner.RemovedItems.Add(item);
- }
- ClearInternal();
- _isCleared = true;
- }
- return true;
- }
-
- private void EnsureValidThread()
- {
- Dispatcher.UIThread.VerifyAccess();
- }
- }
- }
|