How to customize the appointment using DataTemplate in the .NET MAUI Scheduler (SfScheduler)?
The .NET MAUI Scheduler allows you to customize the default appearance of the scheduler appointments using the AppointmentTemplate property of SchedulerMonthView, SchedulerDayView, and SchedulerTimelineView.
The SchedulerAppointment is set as the BindingContext for AppointmentTemplate for both the SchedulerAppointment and the custom data object in AppointmentsSource. You can use the binding context SchedulerAppointment properties in the data template based on your requirement.
STEP 1:
Define the data template for day view appointments.
<DataTemplate x:Key="dayAppointmentTemplate"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="0.1*"/> <RowDefinition Height="0.8*"/> <RowDefinition Height="0.1*"/> </Grid.RowDefinitions> <Grid Grid.Row="0" Background="{Binding Data.Background}" IsClippedToBounds="True"> <Label Text="{Binding Data.EventName}" VerticalOptions="Center" TextColor="White" LineBreakMode="WordWrap" MaxLines="1" FontSize="Caption" FontAttributes="Bold" Margin="5,5,5,0"/> </Grid> <Grid Grid.Row="1" Background="{Binding Data.Background}" Opacity="0.8" IsClippedToBounds="True" > <Grid.RowDefinitions> <RowDefinition Height="0.3*"/> <RowDefinition Height="0.7*"/> </Grid.RowDefinitions> <Image Aspect="AspectFit" VerticalOptions="Center" Margin="0, 10, 0, 10" HorizontalOptions="Center" HeightRequest="{OnPlatform Android= 30, iOS=30, MacCatalyst=50}" WidthRequest="{OnPlatform Android= 30, iOS=30, MacCatalyst=50}" Source="{Binding Data.Location}"/> <Label Text="{Binding Data.Notes}" Grid.Row="1" TextColor="White" LineBreakMode="WordWrap" Margin="3,3,3,0" FontSize="10" /> </Grid> <BoxView Grid.Row="2" Background="{Binding Data.Background}"/> </Grid> </DataTemplate>
STEP 2:
Define the data template for timeline view appointments.
<DataTemplate x:Key="timelineAppointmentTemplate"> <Grid Margin="2,1"> <Grid.ColumnDefinitions> <ColumnDefinition Width="0.1*"/> <ColumnDefinition Width="0.9*"/> </Grid.ColumnDefinitions> <Border StrokeThickness="1" Stroke="{Binding Data.Background}" Background="{Binding Data.Background}" Padding="0" Margin="0" Opacity="0.8"> <Border.StrokeShape> <RoundRectangle CornerRadius="5, 0, 5, 0" /> </Border.StrokeShape> </Border> <Border Grid.Column="1" Background="{Binding Data.Background}" Padding="0" Margin="-1, 0, 0, 0" StrokeThickness="1" Stroke="{Binding Data.Background}"> <Border.StrokeShape> <RoundRectangle CornerRadius="0, 5, 0, 5" /> </Border.StrokeShape> <Label HorizontalTextAlignment="Center" Text="{Binding Data.EventName}" FontSize="10" FontAttributes="Bold" TextColor="White" LineBreakMode="WordWrap" HorizontalOptions="Center" VerticalOptions="Center" /> </Border> </Grid> </DataTemplate>
STEP 3:
Define the data template for month view appointments.
<DataTemplate x:Key="monthAppointmentTemplate"> <Grid Margin="2,1"> <Grid.ColumnDefinitions> <ColumnDefinition Width="0.1*"/> <ColumnDefinition Width="0.9*"/> </Grid.ColumnDefinitions> <Border StrokeThickness="1" Stroke="{Binding Data.Background}" Background="{Binding Data.Background}" Padding="0" Margin="0" Opacity="0.8"> <Border.StrokeShape> <RoundRectangle CornerRadius="5, 0, 5, 0" /> </Border.StrokeShape> </Border> <Border Grid.Column="1" Background="{Binding Data.Background}" Padding="0" Margin="-1, 0, 0, 0" StrokeThickness="1" Stroke="{Binding Data.Background}"> <Border.StrokeShape> <RoundRectangle CornerRadius="0, 5, 0, 5" /> </Border.StrokeShape> <Label Padding="3, 0, 0, 0" HorizontalTextAlignment="Start" Text="{Binding Data.EventName}" FontSize="10" FontAttributes="Bold" MaxLines="1" TextColor="White" LineBreakMode="WordWrap" HorizontalOptions="Start" VerticalOptions="Center" /> </Border> </Grid> </DataTemplate>
STEP 4:
Customize appointment data according to the active view, then bind the templates to the Scheduler.
private void OnSchedulerViewChanged(object? sender, SchedulerViewChangedEventArgs e) { if (this.scheduler == null || e.NewVisibleDates == null) { return; } var startDate = e.NewVisibleDates.FirstOrDefault(); var random = new Random(); appointments = new ObservableCollection<Meeting>(); if (this.scheduler.View == SchedulerView.Week || this.scheduler.View == SchedulerView.WorkWeek) { List<string> eventCollection = new() { "Environmental Discussion", "Health Checkup", "Cancer awareness", "Happiness", "Tourism" }; List<string> notesCollection = new() { "A day that creates awareness to promote the healthy planet and reduce the air pollution crisis on nature earth.", "A day that raises awareness on different healthy issue. It marks the anniversary of the foundation of WHO.", "A day that raises awareness on cancer and its preventive measures. Early detection saves life.", "A general idea is to promote happiness and smile around the world.", "A day that raises awareness on the role of tourism and its effect on social and economic values." }; List<Brush> colorCollection = new() { new SolidColorBrush(Color.FromArgb("#FF56AB56")), new SolidColorBrush(Color.FromArgb("#FF357CD2")), new SolidColorBrush(Color.FromArgb("#FF7FA90E")), new SolidColorBrush(Color.FromArgb("#ff8c00")), new SolidColorBrush(Color.FromArgb("#FF5BBEAF")) }; List<string> imageCollection = new() { "environment_day.png", "health_day.png", "cancer_day.png", "happiness_day.png", "tourism_day.png" }; if (e.NewVisibleDates.Any(d => d.Date == DateTime.Now.Date)) { startDate = startDate.AddDays(1); for (int i = 0; i < 5; i++) { Meeting meeting = new(); meeting.Background = colorCollection[i]; meeting.From = startDate.AddDays(i).AddHours(10); meeting.To = startDate.AddDays(i).AddHours(16); meeting.EventName = eventCollection[i]; meeting.Notes = notesCollection[i]; meeting.Location = imageCollection[i]; appointments.Add(meeting); } } } else if (this.scheduler.View == SchedulerView.TimelineDay || this.scheduler.View == SchedulerView.TimelineWeek || this.scheduler.View == SchedulerView.TimelineWorkWeek) { if (e.NewView == SchedulerView.TimelineDay) { this.scheduler.TimelineView.TimeIntervalWidth = 150; } else { this.scheduler.TimelineView.TimeIntervalWidth = 50; } if (e.OldView == SchedulerView.TimelineDay || e.OldView == SchedulerView.TimelineWeek || e.OldView == SchedulerView.TimelineWorkWeek) { return; } List<Brush> colorCollection = this.GetColorCollection(); List<string> currentDayMeetings = new() { "General Meeting", "Scrum", "Project Plan", "Consulting", "Support", "Yoga Therapy", "Plan Execution", "Project Plan", "Consulting", "Performance Check" }; for (int i = -90; i < 120; i++) { DateTime date = DateTime.Now.Date.AddDays(i); for (int j = 0; j < 2; j++) { Meeting meeting = new(); meeting.Background = colorCollection[random.Next(0, 9)]; meeting.From = date.AddHours(random.Next(7, 16)); meeting.To = meeting.From.AddHours(4); meeting.EventName = currentDayMeetings[random.Next(0, 9)]; appointments.Add(meeting); } } } else { if (e.OldView == e.NewView) { return; } if (e.NewView == SchedulerView.TimelineMonth) { this.scheduler.TimelineView.TimeIntervalWidth = 150; } List<Brush> colorCollection = this.GetColorCollection(); List<string> currentDayMeetings = new() { "General Meeting", "Scrum", "Project Plan", "Consulting", "Support", "Yoga Therapy", "Plan Execution", "Project Plan", "Consulting", "Performance Check" }; for (int month = -3; month < 3; month++) { for (int i = 0; i < 20; i++) { DateTime date = DateTime.Now.Date.AddMonths(month).AddDays(random.Next(0, 30)); Meeting meeting = new(); meeting.Background = colorCollection[random.Next(0, 9)]; meeting.From = date.AddHours(random.Next(9, 13)); meeting.To = meeting.From.AddHours(4); meeting.EventName = currentDayMeetings[random.Next(0, 9)]; appointments.Add(meeting); } } } this.scheduler.AppointmentsSource = appointments; }
STEP 5:
Integrate your customized templates into the Scheduler.
<schedule:SfScheduler x:Name="Scheduler" View="TimelineDay" AllowedViews="Day,Week,WorkWeek,TimelineDay,TimelineWeek,TimelineWorkWeek"> <schedule:SfScheduler.AppointmentMapping> <schedule:SchedulerAppointmentMapping Subject="EventName" StartTime="From" EndTime="To" Background="Background" IsAllDay="IsAllDay" StartTimeZone="StartTimeZone" EndTimeZone="EndTimeZone" RecurrenceExceptionDates="RecurrenceExceptions" RecurrenceRule="RecurrenceRule" RecurrenceId="RecurrenceId"/> </schedule:SfScheduler.AppointmentMapping> <schedule:SfScheduler.MonthView> <schedule:SchedulerMonthView AppointmentTemplate="{StaticResource monthAppointmentTemplate}" AppointmentDisplayMode="Text" > </schedule:SchedulerMonthView> </schedule:SfScheduler.MonthView> <schedule:SfScheduler.TimelineView> <schedule:SchedulerTimelineView AppointmentTemplate="{StaticResource timelineAppointmentTemplate}" /> </schedule:SfScheduler.TimelineView> <scheduler:SfScheduler.DaysView> <scheduler:SchedulerDaysView AppointmentTemplate="{StaticResource dayAppointmentTemplate}"/> </scheduler:SfScheduler.DaysView> <scheduler:SfScheduler.Behaviors> <local:AppearanceCustomizationBehavior/> </scheduler:SfScheduler.Behaviors> </schedule:SfScheduler>
Output
Download the complete sample on GitHub
Conclusion
I hope you enjoyed learning how to customize the appointment using DataTemplate in the .NET MAUI Scheduler.
You can refer to our .NET MAUI Scheduler feature tour page to know about its other groundbreaking feature representations and documentation, and how to quickly get started for configuration specifications.
For current customers, you can check out our components from the License and Downloads page. If you are new to Syncfusion®, you can try our 30-day free trial to check out our other controls.
If you have any queries or require clarifications, please let us know in the comments section below. You can also contact us through our support forums, Direct-Trac, or feedback portal. We are always happy to assist you!