Skip to content

Commit a5a0c96

Browse files
authored
Add default implementation of events to calendar (#183)
2 parents 08d6e79 + fa3ea4a commit a5a0c96

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+1250
-434
lines changed

XCalendar.Core/Interfaces/ICalendar.cs

+13-2
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,24 @@
11
using System;
2-
using System.Collections.ObjectModel;
32
using System.ComponentModel;
43
using XCalendar.Core.Collections;
54
using XCalendar.Core.Enums;
65
using XCalendar.Core.Models;
76

87
namespace XCalendar.Core.Interfaces
98
{
10-
public interface ICalendar<T> : INotifyPropertyChanged where T : ICalendarDay, new()
9+
/// <summary>
10+
/// An interface representing a calendar.
11+
/// </summary>
12+
/// <typeparam name="T">A model implementing <see cref="ICalendarDay{TEvent}"/> to be used to represent each day in a page.</typeparam>
13+
public interface ICalendar<T> : ICalendar<T, IEvent> where T : ICalendarDay<IEvent>, new()
14+
{
15+
}
16+
/// <summary>
17+
/// An interface representing a calendar.
18+
/// </summary>
19+
/// <typeparam name="T">A model implementing <see cref="ICalendarDay{TEvent}"/> to be used to represent each day in a page.</typeparam>
20+
/// <typeparam name="TEvent">A model implementing <see cref="IEvent"/> to be used to represent calendar events.</typeparam>
21+
public interface ICalendar<T, TEvent> : INotifyPropertyChanged where T : ICalendarDay<TEvent>, new() where TEvent : IEvent
1122
{
1223
#region Properties
1324
ObservableRangeCollection<T> Days { get; }
+6-1
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,19 @@
11
using System;
22
using System.ComponentModel;
3+
using XCalendar.Core.Collections;
34

45
namespace XCalendar.Core.Interfaces
56
{
6-
public interface ICalendarDay : INotifyPropertyChanged
7+
public interface ICalendarDay : ICalendarDay<IEvent>
8+
{
9+
}
10+
public interface ICalendarDay<TEvent> : INotifyPropertyChanged where TEvent : IEvent
711
{
812
DateTime DateTime { get; set; }
913
bool IsSelected { get; set; }
1014
bool IsCurrentMonth { get; set; }
1115
bool IsToday { get; set; }
1216
bool IsInvalid { get; set; }
17+
ObservableRangeCollection<TEvent> Events { get; set; }
1318
}
1419
}

XCalendar.Core/Interfaces/IEvent.cs

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
using System;
2+
3+
namespace XCalendar.Core.Interfaces
4+
{
5+
public interface IEvent
6+
{
7+
string Title { get; set; }
8+
string Description { get; set; }
9+
DateTime StartDate { get; set; }
10+
DateTime? EndDate { get; set; }
11+
}
12+
}

XCalendar.Core/Models/Calendar.cs

+64-4
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,22 @@ namespace XCalendar.Core.Models
1616
/// <summary>
1717
/// A class representing a calendar.
1818
/// </summary>
19-
public class Calendar : Calendar<CalendarDay>
19+
public class Calendar : Calendar<CalendarDay, Event>
2020
{
2121
}
2222
/// <summary>
2323
/// A class representing a calendar.
2424
/// </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
2735
{
2836
#region Fields
2937
protected static readonly ReadOnlyCollection<DayOfWeek> DaysOfWeek = DayOfWeekExtensions.DaysOfWeek;
@@ -46,6 +54,7 @@ public class Calendar : Calendar<CalendarDay>
4654
private DateTime? _rangeSelectionStart;
4755
private DateTime? _rangeSelectionEnd;
4856
private SelectionType _selectionType = SelectionType.None;
57+
private ObservableRangeCollection<TEvent> _events = new ObservableRangeCollection<TEvent>();
4958
#endregion
5059

5160
#region Properties
@@ -438,6 +447,31 @@ public SelectionType SelectionType
438447
}
439448
}
440449
}
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+
}
441475
#endregion
442476

443477
#region Events
@@ -472,6 +506,8 @@ public Calendar()
472506
SelectedDates.CollectionChanged += SelectedDates_CollectionChanged;
473507
}
474508

509+
Events.CollectionChanged += Events_CollectionChanged;
510+
475511
//Not needed because days are updated in previous lines of code.
476512
UpdateDays(NavigatedDate);
477513
}
@@ -686,12 +722,13 @@ public virtual void UpdateDay(T day, DateTime newDateTime)
686722
day.IsToday = IsDateTimeToday(day.DateTime);
687723
day.IsSelected = IsDateTimeSelected(day.DateTime);
688724
day.IsInvalid = IsDateTimeInvalid(day.DateTime);
725+
UpdateDayEvents(day);
689726
}
690727
/// <summary>
691728
/// Updates the dates displayed on the calendar.
692729
/// </summary>
693730
/// <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)
695732
{
696733
OnDaysUpdating();
697734

@@ -764,6 +801,25 @@ public void UpdateDays(DateTime navigationDate)
764801

765802
OnDaysUpdated();
766803
}
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+
}
767823
/// <summary>
768824
/// 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"/>).
769825
/// </summary>
@@ -968,6 +1024,10 @@ private int CoerceRows(int value)
9681024
{
9691025
return AutoRows ? GetMonthRows(NavigatedDate, AutoRowsIsConsistent, StartOfWeek) : value;
9701026
}
1027+
private void Events_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
1028+
{
1029+
UpdateDays(NavigatedDate);
1030+
}
9711031
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
9721032
{
9731033
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));

XCalendar.Core/Models/CalendarDay.cs

+22-1
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,24 @@
11
using System;
22
using System.ComponentModel;
33
using System.Runtime.CompilerServices;
4+
using XCalendar.Core.Collections;
45
using XCalendar.Core.Interfaces;
56

67
namespace XCalendar.Core.Models
78
{
8-
public class CalendarDay : ICalendarDay
9+
public class CalendarDay : CalendarDay<Event>
10+
{
11+
}
12+
13+
public class CalendarDay<TEvent> : ICalendarDay<TEvent> where TEvent : IEvent
914
{
1015
#region Fields
1116
private DateTime _dateTime = DateTime.Today;
1217
private bool _isSelected;
1318
private bool _isCurrentMonth;
1419
private bool _isToday;
1520
private bool _isInvalid;
21+
private ObservableRangeCollection<TEvent> _events = new ObservableRangeCollection<TEvent>();
1622
#endregion
1723

1824
#region Properties
@@ -91,6 +97,21 @@ public bool IsInvalid
9197
}
9298
}
9399
}
100+
public ObservableRangeCollection<TEvent> Events
101+
{
102+
get
103+
{
104+
return _events;
105+
}
106+
set
107+
{
108+
if (_events != value)
109+
{
110+
_events = value;
111+
OnPropertyChanged();
112+
}
113+
}
114+
}
94115
#endregion
95116

96117
#region Events

XCalendar.Core/Models/Event.cs

+91
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
using System;
2+
using System.ComponentModel;
3+
using System.Runtime.CompilerServices;
4+
using XCalendar.Core.Interfaces;
5+
6+
namespace XCalendar.Core.Models
7+
{
8+
public class Event : IEvent, INotifyPropertyChanged
9+
{
10+
#region Fields
11+
private string _title;
12+
private string _description;
13+
private DateTime _startDate = DateTime.Today;
14+
private DateTime? _endDate = DateTime.Today;
15+
#endregion
16+
17+
#region Properties
18+
public string Title
19+
{
20+
get
21+
{
22+
return _title;
23+
}
24+
set
25+
{
26+
if (_title != value)
27+
{
28+
_title = value;
29+
OnPropertyChanged();
30+
}
31+
}
32+
}
33+
public string Description
34+
{
35+
get
36+
{
37+
return _description;
38+
}
39+
set
40+
{
41+
if (_description != value)
42+
{
43+
_description = value;
44+
OnPropertyChanged();
45+
}
46+
}
47+
}
48+
public DateTime StartDate
49+
{
50+
get
51+
{
52+
return _startDate;
53+
}
54+
set
55+
{
56+
if (_startDate != value)
57+
{
58+
_startDate = value;
59+
OnPropertyChanged();
60+
}
61+
}
62+
}
63+
public DateTime? EndDate
64+
{
65+
get
66+
{
67+
return _endDate;
68+
}
69+
set
70+
{
71+
if (_endDate != value)
72+
{
73+
_endDate = value;
74+
OnPropertyChanged();
75+
}
76+
}
77+
}
78+
#endregion
79+
80+
#region Events
81+
public event PropertyChangedEventHandler PropertyChanged;
82+
#endregion
83+
84+
#region Methods
85+
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
86+
{
87+
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
88+
}
89+
#endregion
90+
}
91+
}
+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
using Xamarin.Forms;
2+
using XCalendar.Core.Models;
3+
4+
namespace XCalendar.Forms.Models
5+
{
6+
public class ColoredEvent : Event
7+
{
8+
#region Fields
9+
private Color _color;
10+
#endregion
11+
12+
#region Properties
13+
public Color Color
14+
{
15+
get
16+
{
17+
return _color;
18+
}
19+
set
20+
{
21+
if (_color != value)
22+
{
23+
_color = value;
24+
OnPropertyChanged();
25+
}
26+
}
27+
}
28+
#endregion
29+
}
30+
}

XCalendar.Forms/Views/CalendarView.xaml.cs

+4-4
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ public DateTime NavigatedDate
1818
get { return (DateTime)GetValue(NavigatedDateProperty); }
1919
set { SetValue(NavigatedDateProperty, value); }
2020
}
21-
public IEnumerable<ICalendarDay> Days
21+
public IEnumerable<object> Days
2222
{
23-
get { return (IEnumerable<ICalendarDay>)GetValue(DaysProperty); }
23+
get { return (IEnumerable<object>)GetValue(DaysProperty); }
2424
set { SetValue(DaysProperty, value); }
2525
}
2626
public IList<DayOfWeek> DaysOfWeek
@@ -114,7 +114,7 @@ public DataTemplate DayTemplate
114114

115115
#region Bindable Properties Initialisers
116116
public static readonly BindableProperty NavigatedDateProperty = BindableProperty.Create(nameof(NavigatedDate), typeof(DateTime), typeof(CalendarView), DateTime.Today);
117-
public static readonly BindableProperty DaysProperty = BindableProperty.Create(nameof(DaysProperty), typeof(IEnumerable<ICalendarDay>), typeof(CalendarView), propertyChanged: DaysPropertyChanged);
117+
public static readonly BindableProperty DaysProperty = BindableProperty.Create(nameof(DaysProperty), typeof(IEnumerable<object>), typeof(CalendarView), propertyChanged: DaysPropertyChanged);
118118
public static readonly BindableProperty DaysOfWeekProperty = BindableProperty.Create(nameof(DaysOfWeek), typeof(IList<DayOfWeek>), typeof(CalendarView), propertyChanged: DaysOfWeekPropertyChanged);
119119
public static readonly BindableProperty RightArrowCommandProperty = BindableProperty.Create(nameof(RightArrowCommand), typeof(object), typeof(CalendarView));
120120
public static readonly BindableProperty RightArrowCommandParameterProperty = BindableProperty.Create(nameof(RightArrowCommandParameter), typeof(object), typeof(CalendarView));
@@ -148,7 +148,7 @@ public CalendarView()
148148
private static void DaysPropertyChanged(BindableObject bindable, object oldValue, object newValue)
149149
{
150150
CalendarView control = (CalendarView)bindable;
151-
IEnumerable<ICalendarDay> newDays = (IEnumerable<ICalendarDay>)newValue;
151+
IEnumerable<object> newDays = (IEnumerable<object>)newValue;
152152

153153
control.MainDaysView.Days = newDays;
154154
}

0 commit comments

Comments
 (0)