@@ -16,14 +16,22 @@ namespace XCalendar.Core.Models
16
16
/// <summary>
17
17
/// A class representing a calendar.
18
18
/// </summary>
19
- public class Calendar : Calendar < CalendarDay >
19
+ public class Calendar : Calendar < CalendarDay , Event >
20
20
{
21
21
}
22
22
/// <summary>
23
23
/// A class representing a calendar.
24
24
/// </summary>
25
- /// <typeparam name="T">A model implementing <see cref="ICalendarDay"/> to be used to represent each day in a page.</typeparam>
26
- public class Calendar < T > : ICalendar < T > where T : ICalendarDay , new ( )
25
+ /// <typeparam name="T">A model implementing <see cref="ICalendarDay{TEvent}"/> to be used to represent each day in a page.</typeparam>
26
+ public class Calendar < T > : Calendar < T , Event > where T : ICalendarDay < Event > , new ( )
27
+ {
28
+ }
29
+ /// <summary>
30
+ /// A class representing a calendar.
31
+ /// </summary>
32
+ /// <typeparam name="T">A model implementing <see cref="ICalendarDay{TEvent}"/> to be used to represent each day in a page.</typeparam>
33
+ /// <typeparam name="TEvent">A model implementing <see cref="IEvent"/> to be used to represent calendar events.</typeparam>
34
+ public class Calendar < T , TEvent > : ICalendar < T , TEvent > where T : ICalendarDay < TEvent > , new ( ) where TEvent : IEvent
27
35
{
28
36
#region Fields
29
37
protected static readonly ReadOnlyCollection < DayOfWeek > DaysOfWeek = DayOfWeekExtensions . DaysOfWeek ;
@@ -46,6 +54,7 @@ public class Calendar : Calendar<CalendarDay>
46
54
private DateTime ? _rangeSelectionStart ;
47
55
private DateTime ? _rangeSelectionEnd ;
48
56
private SelectionType _selectionType = SelectionType . None ;
57
+ private ObservableRangeCollection < TEvent > _events = new ObservableRangeCollection < TEvent > ( ) ;
49
58
#endregion
50
59
51
60
#region Properties
@@ -438,6 +447,31 @@ public SelectionType SelectionType
438
447
}
439
448
}
440
449
}
450
+ public ObservableRangeCollection < TEvent > Events
451
+ {
452
+ get
453
+ {
454
+ return _events ;
455
+ }
456
+ set
457
+ {
458
+ if ( _events != value )
459
+ {
460
+ if ( _events != null )
461
+ {
462
+ _events . CollectionChanged -= Events_CollectionChanged ;
463
+ }
464
+
465
+ if ( value != null )
466
+ {
467
+ value . CollectionChanged += Events_CollectionChanged ;
468
+ }
469
+
470
+ _events = value ;
471
+ OnPropertyChanged ( ) ;
472
+ }
473
+ }
474
+ }
441
475
#endregion
442
476
443
477
#region Events
@@ -472,6 +506,8 @@ public Calendar()
472
506
SelectedDates . CollectionChanged += SelectedDates_CollectionChanged ;
473
507
}
474
508
509
+ Events . CollectionChanged += Events_CollectionChanged ;
510
+
475
511
//Not needed because days are updated in previous lines of code.
476
512
UpdateDays ( NavigatedDate ) ;
477
513
}
@@ -686,12 +722,13 @@ public virtual void UpdateDay(T day, DateTime newDateTime)
686
722
day . IsToday = IsDateTimeToday ( day . DateTime ) ;
687
723
day . IsSelected = IsDateTimeSelected ( day . DateTime ) ;
688
724
day . IsInvalid = IsDateTimeInvalid ( day . DateTime ) ;
725
+ UpdateDayEvents ( day ) ;
689
726
}
690
727
/// <summary>
691
728
/// Updates the dates displayed on the calendar.
692
729
/// </summary>
693
730
/// <param name="navigationDate">The <see cref="DateTime"/> who's month will be used to update the dates.</param>
694
- public void UpdateDays ( DateTime navigationDate )
731
+ public virtual void UpdateDays ( DateTime navigationDate )
695
732
{
696
733
OnDaysUpdating ( ) ;
697
734
@@ -764,6 +801,25 @@ public void UpdateDays(DateTime navigationDate)
764
801
765
802
OnDaysUpdated ( ) ;
766
803
}
804
+ public virtual void UpdateDayEvents ( T day )
805
+ {
806
+ IEnumerable < TEvent > events = Events . Where ( x => day . DateTime . Date >= x . StartDate && ( x . EndDate == null || day . DateTime . Date < x . EndDate ) ) ;
807
+
808
+ //No use in replacing the collection if the source and target are both empty.
809
+ if ( day . Events . Count == 0 && ! events . Any ( ) )
810
+ {
811
+ return ;
812
+ }
813
+
814
+ //SequenceEqual could be omitted to improve performance but in the vast majority of cases there won't even be more than 5 events in one day, so impact on performance should be negligible
815
+ //compared to always changing the collection.
816
+ if ( day . Events . SequenceEqual ( events ) )
817
+ {
818
+ return ;
819
+ }
820
+
821
+ day . Events . ReplaceRange ( events ) ;
822
+ }
767
823
/// <summary>
768
824
/// Navigates the calendar by the specified <see cref="TimeSpan"/> using the navigation rule properties set in the calendar (<see cref="NavigationLowerBound"/>, <see cref="NavigationUpperBound"/> <see cref="NavigationLoopMode"/>).
769
825
/// </summary>
@@ -968,6 +1024,10 @@ private int CoerceRows(int value)
968
1024
{
969
1025
return AutoRows ? GetMonthRows ( NavigatedDate , AutoRowsIsConsistent , StartOfWeek ) : value ;
970
1026
}
1027
+ private void Events_CollectionChanged ( object sender , NotifyCollectionChangedEventArgs e )
1028
+ {
1029
+ UpdateDays ( NavigatedDate ) ;
1030
+ }
971
1031
protected virtual void OnPropertyChanged ( [ CallerMemberName ] string propertyName = null )
972
1032
{
973
1033
PropertyChanged ? . Invoke ( this , new PropertyChangedEventArgs ( propertyName ) ) ;
0 commit comments