This is a .NET MAUI port of the lilcodelab Xamarin.Forms Calendar Plugin
Available on NuGet: https://www.nuget.org/packages/Plugin.Maui.Calendar
Simple cross-platform plugin for Calendar control featuring:
- Displaying events by binding EventCollection
- Localization support with System.Globalization.CultureInfo
- Customizable colors, day view sizes/label styles, custom Header/Footer template support
- UI reactive to EventCollection, Culture, and other changes
V2.0.0
- Updated to .NET 9
- Optimized startup time: iOS 20 % / Android 40 %
- Fixed memory leaks*
- Revamped calendar structure
- Added Styles (check Available Styles section) that replace some properties
- Added WeekendTitleStyle
- Added sample page (Default calendar) to test memory leaks with MemoryToolkit.Maui )
- Updated samples
- Added native digits support (added UseNativeDigits Property)
- Added OtherMonthWeekIsVisible and DayViewBorderMargin properties
Properties that Styles have replaced
DayViewFontSize --> DaysLabelStyle
MonthLabelColor --> MonthLabelStyle
YearLabelColor --> YearLabelStyle
ArrowsBackgroundColor, ArrowsBorderColor, ArrowsBorderWidth, ArrowsFontAttribute, ArrowsFontSize, ArrowsFontFamily, ArrowsColor -->
ArrowsSymbolPrev --> PreviousMonthArrowButtonStyle
ArrowsSymbolNext --> NextMonthArrowButtonStyle
ArrowsSymbolPrev --> PreviousYearArrowButtonStyle
ArrowsSymbolNext --> NextYearArrowButtonStyle
ArrowsFontFamily, ArrowsColor --> FooterArrowLabelStyle
SelectedDateColor --> SelectedDateLabelStyle
DaysTitleHeight, DaysTitleColor --> DaysTitleLabelStyle
DaysTitleHeight, DaysTitleWeekendColor --> WeekendTitleStyle
⚠️ Breaking Change:
TheSelectedDates
property is now anObservableCollection<DateTime>
.
To ensure the calendar updates when dates are added/removed, use:SelectedDates = new ObservableCollection<DateTime> { ... };Do not use
List<DateTime>
forSelectedDates
binding.
V1.0.x
- Removed all the platform-specific code, hence it supports all available .NET MAUI backends: iOS, Android, Windows, Mac, Tizen (not tested yet)
- Added Multiselection support (Latest PR that was not merged previously)
- Refactored and revamped code
- Updated to .NET 8
- Added OnShownDateChangedCommand so we can take action when a date is changed.
- Added new property OtherMonthSelectedDayColor
- Fixed bug with OtherMonthDayIsVisible property
- Added a weekend calendar sample
- Added a Windows 11 calendar sample
- Added theme support
- Added new property FirstDayOfWeek
- Added support for multiple event dots (multidots) in calendar
- Added MonthChanged Event and MonthChangedCommand
- Added AllowDeselecting property
- Added SelectedDatesRangeBackgroundColor property
- Updated samples
Android | iOS |
---|---|
![]() |
![]() |
Win | Mac |
---|---|
![]() |
![]() |
Theme support
Ligth | Dark | Settings |
---|---|---|
![]() |
![]() |
![]() |
Culture support
Android | iOS |
---|---|
![]() |
![]() |
Windows 11 calendar
Win | Mac |
---|---|
![]() |
![]() |
Weekend calendar
Android | IOS |
---|---|
![]() |
![]() |
To get started just install the package via Nuget. You can take a look on the sample app to get started or continue reading.
Reference the following xmlns to your page:
xmlns:controls="clr-namespace:Plugin.Maui.Calendar.Controls;assembly=Plugin.Maui.Calendar"
Basic control usage:
<controls:Calendar
Day="14"
Month="5"
Year="2019"
VerticalOptions="Fill"
HorizontalOptions="Fill"/>
Bindable properties:
Culture
CultureInfo calender culture/languageDay
int currently viewing dayMonth
int currently viewing monthYear
int currently viewing yearEvents
EventCollection (from package) your events for calender- Custom colors, fonts, sizes ...
Remark: You can use ShownDate
as an alternative to Year
, Month
and Day
<controls:Calendar
ShownDate="2019-05-14"
VerticalOptions="Fill"
HorizontalOptions="Fill"/>
In your XAML, add the data template for events, and bind the events collection, example:
<controls:Calendar
Events="{Binding Events}">
<controls:Calendar.EventTemplate>
<DataTemplate>
<StackLayout
Padding="15,0,0,0">
<Label
Text="{Binding Name}"
FontAttributes="Bold"
FontSize="Medium" />
<Label
Text="{Binding Description}"
FontSize="Small"
LineBreakMode="WordWrap" />
</StackLayout>
</DataTemplate>
</controls:Calendar.EventTemplate>
</controls:Calendar>
In your ViewModel reference the following namespace:
using Plugin.Maui.Calendar.Models;
Add property for Events:
public EventCollection Events { get; set; }
Initialize Events with your data:
Events = new EventCollection
{
[DateTime.Now] = new List<EventModel>
{
new() { Name = "Cool event1", Description = "This is Cool event1's description!" },
new() { Name = "Cool event2", Description = "This is Cool event2's description!" }
},
// 5 days from today
[DateTime.Now.AddDays(5)] = new List<EventModel>
{
new() { Name = "Cool event3", Description = "This is Cool event3's description!" },
new() { Name = "Cool event4", Description = "This is Cool event4's description!" }
},
// 3 days ago
[DateTime.Now.AddDays(-3)] = new List<EventModel>
{
new() { Name = "Cool event5", Description = "This is Cool event5's description!" }
},
// custom date
[new DateTime(2024, 3, 16)] = new List<EventModel>
{
new() { Name = "Cool event6", Description = "This is Cool event6's description!" }
}
};
Initialize Events with your data and a different dot color per day:
Events = new EventCollection
{
//2 days ago
[DateTime.Now.AddDays(-2)] = new DayEventCollection<EventModel>(Colors.Purple, Colors.Purple)
{
new() { Name = "Cool event1", Description = "This is Cool event1's description!" },
new() { Name = "Cool event2", Description = "This is Cool event2's description!" }
},
// 5 days ago
[DateTime.Now.AddDays(-5)] = new DayEventCollection<EventModel>(Colors.Blue, Colors.Blue)
{
new() { Name = "Cool event3", Description = "This is Cool event3's description!" },
new() { Name = "Cool event4", Description = "This is Cool event4's description!" }
},
};
//4 days ago
Events.Add(DateTime.Now.AddDays(-4), new DayEventCollection<EventModel>(GenerateEvents(10, "Cool")) { EventIndicatorColor = Colors.Green, EventIndicatorSelectedColor = Colors.Green });
Where EventModel
is just an example, it can be replaced by any data model you desire.
EventsCollection
is just a wrapper over Dictionary<DateTime, ICollection>
exposing custom Add
method and this[DateTime]
indexer which internally extracts the .Date
component of DateTime
values and uses it as a key in this dictionary.
DayEventCollection
is just a wrapper over List<T>
exposing custom properties EventIndicatorColor
and EventIndicatorSelectedColor
for assigning a custom color to the dot.
The DayTappedCommand is triggered when a user taps on a specific day in the calendar.
XAML Usage:
DayTappedCommand="{Binding DayTappedCommand}"
In your ViewModel add property for Culture:
public CultureInfo Culture => new CultureInfo("hr-HR")
In XAML add Culture binding
<controls:Calendar
Culture="{Binding Culture}"/>
</controls:Calendar>
Sample properties:
EventIndicatorColor="Red"
EventIndicatorSelectedColor="White"
DeselectedDayTextColor="Blue"
OtherMonthDayColor="Gray"
SelectedDayTextColor="Cyan"
SelectedDayBackgroundColor="DarkCyan"
SelectedTodayTextColor="Green"
TodayOutlineColor="Blue"
TodayFillColor="Silver"
TodayTextColor="Yellow"
OtherMonthSelectedDayColor="HotPink"
Style Key | Based On (DefaultStyles ) |
---|---|
DaysLabelStyle |
DefaultStyles.DefaultLabelStyle |
MonthLabelStyle |
DefaultStyles.DefaultMonthLabelStyle |
YearLabelStyle |
DefaultStyles.DefaultYearLabelStyle |
PreviousMonthArrowButtonStyle |
DefaultStyles.DefaultPreviousMonthArrowButtonStyle |
NextMonthArrowButtonStyle |
DefaultStyles.DefaultNextMonthArrowButtonStyle |
PreviousYearArrowButtonStyle |
DefaultStyles.DefaultPreviousYearArrowButtonStyle |
NextYearArrowButtonStyle |
DefaultStyles.DefaultNextYearArrowButtonStyle |
FooterArrowLabelStyle |
DefaultStyles.DefaultFooterArrowLabelStyle |
SelectedDateLabelStyle |
DefaultStyles.DefaultSelectedDateLabelStyle |
WeekdayTitleStyle |
DefaultStyles.DefaultDaysTitleLabelStyle |
WeekendTitleStyle |
DefaultStyles.DefaultWeekendTitleStyle |
FirstDayOfWeek="Monday"
UseNativeDigits="True"
OtherMonthWeekIsVisible="False"
DayViewBorderMargin
You can set the layout of the calendar with the property CalendarLayout
-
Available layouts are:
OneWeek
- only one week is shownTwoWeeks
- two weeks are shownMonth
- the whole month is shown (default value)
CalendarLayout="Month"
You can also choose to display the shown week number instead of the month name
CalendarLayout="Week"
WeekViewUnit="WeekNumber"
You can customize how the event indication will look with the property EventIndicatorType
- Available indicators are:
BottomDot
- event indicator as dot bellow of date in the calendar (default value)TopDot
- event indicator as the dot on top of the date in the calendarBackground
- event indicator as colored background in calendarBackgroundFull
// event indicator as larger size colored background in the calendar
EventIndicatorType="Background"
You can write your own customizations commands for swipe.
SwipeLeftCommand="{Binding SwipeLeftCommand}"
SwipeRightCommand="{Binding SwipeRightCommand}"
SwipeUpCommand="{Binding SwipeUpCommand}"
You can also disable default swipe actions.
SwipeToChangeMonthEnabled="False"
SwipeUpToHideEnabled="False"
You can either use the Calender
class implementation for a single selection mode, multiselection mode or RangeSelectionCalendar
for a range selection mode.
<plugin:Calendar
SelectedDate="{Binding SelectedDate}"/>
On the RangeSelectionCalendar
you can use binding for start date SelectedStartDate
and end date SelectedEndDate
or get list of selected dates with SelectedDates
.
<plugin:RangeSelectionCalendar
x:Name="rangedCalendar"
SelectedDates="{Binding SelectedDates}"
SelectedEndDate="{Binding SelectedEndDate}"
SelectedStartDate="{Binding SelectedStartDate}">
On the MultiselectionCalendar
you can select multiple separate dates
plugin:MultiSelectionCalendar
Events="{Binding Events}"
MaximumDate="{Binding MaximumDate}"
MinimumDate="{Binding MinimumDate}"
Month="{Binding Month}" >
Remark: Don't use both SelectedDates
and SelectedStartDate
/SelectedEndDate
Enable/Disable the visibility of the Events scrollview panel at the bottom Sample properties:
EventsScrollViewVisible="True"
There are several templates that can be used to customize the calendar. You can find an example for each one in the AdvancedPage.xaml. You can create your own custom control file or you can also write customization directly inside of Templates.
These sections provide customization over appearance of the controls of the calendar, like showing the selected month and year, month selection controls etc.
Customize the header section (top of the calendar control). Example from AdvancedPage.xaml
<plugin:Calendar.HeaderSectionTemplate>
<controls:CalendarHeader />
</plugin:Calendar.HeaderSectionTemplate>
Customize the footer section (under the calendar part, above the events list). Example from AdvancedPage.xaml
<plugin:Calendar.FooterSectionTemplate>
<DataTemplate>
<controls:CalendarFooter />
</DataTemplate>
</plugin:Calendar.FooterSectionTemplate>
Customize the bottom section (at the bottom of the calendar control, below the events list). Example from AdvancedPage.xaml
<plugin:Calendar.BottomSectionTemplate>
<controls:CalendarBottom />
</plugin:Calendar.BottomSectionTemplate>
These templates provide customization for the events list.
Customize the appearance of the events section. Example from AdvancedPage.xaml
<plugin:Calendar.EventTemplate>
<DataTemplate>
<controls:CalenderEvent CalenderEventCommand="{Binding BindingContext.EventSelectedCommand, Source={x:Reference advancedCalendarPage}}" />
</DataTemplate>
</plugin:Calendar.EventTemplate>
Customize what to show in case the selected date has no events. Example from AdvancedPage.xaml
<plugin:Calendar.EmptyTemplate>
<DataTemplate>
<StackLayout>
<Label Text="NO EVENTS FOR THE SELECTED DATE" HorizontalTextAlignment="Center" Margin="0,5,0,5" />
</StackLayout>
</DataTemplate>
</plugin:Calendar.EmptyTemplate>