In this blog, we’ll see how to load appointments in the .NET MAUI Scheduler with the SQLite database, perform CRUD actions (create, read, update, and delete) on the SQLite database, and dynamically update the changes in the .NET MAUI Scheduler.
The Syncfusion .NET MAUI Scheduler is a powerful tool that provides a wide range of scheduling functionalities, allowing for the efficient management of appointments.
SQLite is a lightweight, open-source, and self-contained relational database management system (RDBMS). It is popular for embedded systems, mobile apps, and desktop software due to its ease of use and efficiency. It seamlessly integrates with .NET MAUI apps to load and save data objects in shared code.
Agenda:
- Create SQLite connection, define model, and populate appointments.
- Build a schedule appointment editor.
- Perform CRUD operations on SQLite database and update .NET MAUI Scheduler.
Let’s get started!
Note: Before proceeding, see the getting started with .NET MAUI Scheduler documentation.
Create SQLite connection, define model, and populate appointments
Let’s explore the simple steps to connect SQLite with the Syncfusion .NET MAUI Scheduler.
Step 1: Install the required package
First, we are going to install the sqlite-net-pcl package to connect the SQLite database.
Refer to the following image.
Step 2: Create the SQLite connection
Next, define the SQLite connection using the SQLiteConnection API and set up the database path property in the SchedulerDatabase.cs file.
readonly SQLiteConnection _database;
public SchedulerDatabase(string dbPath)
{
_database = new SQLiteConnection(dbPath);
}
Now, create an instance for the SQLite connection with the database Path property and initialize it in the App.Xaml.cs file to use the database.
Refer to the following code example.
public static SchedulerDatabase Database
{
get
{
if (database == null)
{
database = new SchedulerData-base(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "MAUISchedulerDatabase.db3"));
}
return database;
}
}
Step 3: Define the database table model
Then, create a model class named Appointment to hold the property values from the database table in the Appointment.cs file.
public class Appointment
{
[PrimaryKey, AutoIncrement, Unique]
public int ID { get; set; }
public DateTime From { get; set; }
public DateTime To { get; set; }
public bool AllDay { get; set; }
public string EventName { get; set; }
public string Notes { get; set; }
}
Subsequently, create a table named Appointment in that SQLite database.
SchedulerDatabase.cs
_database.CreateTable<Appointment>();
Step 4: Populate SQLite database appointments
In the SchedulerViewModel class, populate the data from the SQLite database.
public ObservableCollection<SchedulerAppointment> Appointments { get; set; }
var dataBaseAppointments = App.Database.GetSchedulerAppointment();
if (dataBaseAppointments != null && dataBaseAppointments.Count > 0)
{
foreach (Appointment appointment in dataBaseAppointments)
{
Appointments.Add(new SchedulerAppointment()
{
StartTime = appointment.From,
EndTime = appointment.To,
Subject = appointment.EventName,
IsAllDay = appointment.AllDay,
Id = appointment.ID
});
}
}
Then, retrieve the appointments from the SQLite database in the SchedulerDatabase.cs file.
public List<Appointment> GetSchedulerAppointment()
{
return _database.Table<Appointment>().ToList();
}
Step 5: Bind appointments to the Scheduler
Initialize the .NET MAUI Scheduler control and bind its AppointmentsSource property to the Appointments property of the SchedulerViewModel class.
MainPage.xaml
xmlns:scheduler="clr-namespace:Syncfusion.Maui.Scheduler;assembly=Syncfusion.Maui.Scheduler"
<ContentPage.BindingContext>
<local:SchedulerViewModel/>
</ContentPage.BindingContext>
<scheduler:SfScheduler x:Name="Scheduler"
View="Week"
Tapped="Scheduler_Tapped"
AppointmentsSource="{Binding Appointments}"
ShowWeekNumber="True"
AllowedViews="Day,Week,WorkWeek,Agenda,Month,TimelineDay,TimelineWeek,TimelineWorkWeek,TimelineMonth">
</scheduler:SfScheduler>
After executing the previous code examples, we’ll get output like in the following image.
Build a schedule appointment editor
Create an appointment editor that enables the addition, saving, and deletion of appointments in the .NET MAUI Scheduler.
Refer to the following code example to create a model class to store the basic details of the appointment editor in the AppointmentEditorModel.cs file.
public class AppointmentEditorModel : INotifyPropertyChanged
{
private string subject , notes;
private TimeSpan startTime , endTime;
private bool isAllDay , isEditorEnabled= true;
private DateTime startDate, endDate;
public string Subject
{
get { return subject; }
set
{
subject = value;
RaisePropertyChanged(nameof(this.Subject));
}
}
public string Notes
{
get { return notes; }
set
{
notes = value;
RaisePropertyChanged(nameof(this.Notes));
}
}
public TimeSpan StartTime
{
get { return startTime; }
set
{
startTime = value;
RaisePropertyChanged(nameof(this.StartTime));
}
}
public TimeSpan EndTime
{
get { return endTime; }
set
{
endTime = value;
RaisePropertyChanged(nameof(this.EndTime));
}
}
public bool IsAllDay
{
get { return isAllDay; }
set
{
isAllDay = value;
RaisePropertyChanged(nameof(this.IsAllDay));
}
}
public DateTime StartDate
{
get { return startDate; }
set
{
startDate = value;
RaisePropertyChanged(nameof(this.StartDate));
}
}
public DateTime EndDate
{
get { return endDate; }
set
{
endDate = value;
RaisePropertyChanged(nameof(this.EndDate));
}
}
public bool IsEditorEnabled
{
get { return isEditorEnabled; }
set
{
isEditorEnabled = value;
RaisePropertyChanged(nameof(this.IsEditorEnabled));
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string propertyname)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyname));
}
}
}
Now, let’s create the appointment editor using the.NET MAUI Popup and Text Input Layout controls. Ensure that the AppointmentEditorModel property is correctly bound in each appointment editor, allowing seamless two-way value updates between the appointment and the editor.
MainPage.xaml
xmlns:inputLayout="clr-namespace:Syncfusion.Maui.Core;assembly=Syncfusion.Maui.Core"
xmlns:popup="clr-namespace:Syncfusion.Maui.Popup;assembly=Syncfusion.Maui.Popup"
<ContentPage.BindingContext>
<local:SchedulerViewModel/>
</ContentPage.BindingContext>
<popup:SfPopup x:Name="sfPopup" IsOpen="{Binding IsOpen}" BindingContext="{Binding}" WidthRequest="550" HeightRequest="500" AutoSizeMode="Both" ShowHeader="False" ShowFooter="False">
<popup:SfPopup.ContentTemplate>
<DataTemplate>
<Grid RowDefinitions="*,auto" Margin="20">
<ScrollView>
<StackLayout>
<inputLayout:SfTextInputLayout x:Name="eventName_layout" Hint="Event name" ContainerBackground="Transparent" OutlineCornerRadius="8" ContainerType="Outlined">
<Entry x:Name="eventNameText" Text="{Binding AppointmentEditorModel.Subject}" />
</inputLayout:SfTextInputLayout>
<Grid ColumnDefinitions="0.5*,0.5*">
<inputLayout:SfTextInputLayout Hint="Start date" OutlineCornerRadius="8" ContainerBackground="Transparent" ContainerType="Outlined">
<DatePicker x:Name="startDate_picker" Date="{Binding AppointmentEditorModel.StartDate}" />
</inputLayout:SfTextInputLayout>
<inputLayout:SfTextInputLayout Grid.Column="1" Margin="10,0,0,0" Hint="Start time" OutlineCornerRadius="8" ContainerBackground="Transparent" ContainerType="Outlined">
<TimePicker x:Name="startTime_picker" IsEnabled="{Binding AppointmentEditorModel.IsEditorEnabled}" VerticalOptions="Start" Time="{Binding AppointmentEditorModel.StartTime, Mode=TwoWay}" />
</inputLayout:SfTextInputLayout>
</Grid>
<Grid ColumnDefinitions="0.5*,0.5*">
<inputLayout:SfTextInputLayout Hint="End date" OutlineCornerRadius="8" ContainerBackground="Transparent" ContainerType="Outlined">
<DatePicker x:Name="endDate_picker" Date="{Binding AppointmentEditorModel.EndDate}" />
</inputLayout:SfTextInputLayout>
<inputLayout:SfTextInputLayout Hint="End time" Margin="10,0,0,0" Grid.Column="1" OutlineCornerRadius="8" ContainerBackground="Transparent" ContainerType="Outlined">
<TimePicker x:Name="endTime_picker" IsEnabled="{Binding AppointmentEditorModel.IsEditorEnabled}" HorizontalOptions="Start" Time="{Binding AppointmentEditorModel.EndTime}" />
</inputLayout:SfTextInputLayout>
</Grid>
<Grid Margin="2,-12,0,0" x:Name="allDay" VerticalOptions="Start" ColumnDefinitions="50,*">
<Label Grid.Column="0" VerticalTextAlignment="Center" Text="AllDay"/>
<Switch Toggled="SwitchAllDay_Toggled" IsToggled="{Binding AppointmentEditorModel.IsAllDay}" Margin="10,0,0,0" x:Name="switchAllDay" Grid.Column="1" HorizontalOptions="Start" VerticalOptions="Center" />
</Grid>
<inputLayout:SfTextInputLayout x:Name="organizer_layout" Hint="Notes" OutlineCornerRadius="8" ContainerBackground="Transparent" ContainerType="Outlined">
<Editor x:Name="organizerText" Text="{Binding AppointmentEditorModel.Notes}" />
</inputLayout:SfTextInputLayout>
</StackLayout>
</ScrollView>
<Grid HeightRequest="40" Grid.Row="1" ColumnDefinitions="*,auto">
<Button x:Name="DeleteButton" Command="{Binding DeleteAppointment}" WidthRequest="80" Text="Delete" HorizontalOptions="Start" />
<HorizontalStackLayout HorizontalOptions="End" Grid.Column="1">
<Button x:Name="cancelButton" WidthRequest="80" Text="Cancel" Command="{Binding CancelEditAppointment}" />
<Button Margin="10,0,0,0" x:Name="saveButton" Command="{Binding AddAppointment}" Text="Save" WidthRequest="80" TextColor="White" />
</HorizontalStackLayout>
</Grid>
</Grid>
</DataTemplate>
</popup:SfPopup.ContentTemplate>
</popup:SfPopup>
Refer to the following code example to initialize the AppointmentEditorModel in the SchedulerViewModel.cs file.
public AppointmentEditorModel AppointmentEditorModel { get; set; }
this.AppointmentEditorModel = new AppointmentEditorModel();
private bool isOpen;
public bool IsOpen
{
get { return isOpen; }
set
{
isOpen = value;
OnPropertyChanged(nameof(this.IsOpen));
}
}
The appointment editor pop-up will be displayed upon tapping the scheduler, providing the options to add, edit, or delete the appointments. Refer to the following code examples.
MainPage.xaml.cs
private void Scheduler_Tapped(object sender, SchedulerTappedEventArgs e)
{
if (this.BindingContext is SchedulerViewModel schedulerViewModel)
{
SchedulerAppointment appointment;
DateTime selectedDate;
if (e.Appointments != null && e.Appointments.Count > 0)
{
appointment = (SchedulerAppointment)e.Appointments[0];
selectedDate = appointment.StartTime;
}
else
{
appointment = null;
selectedDate = (DateTime)e.Date;
}
schedulerViewModel.UpdateEditor(appointment, selectedDate);
sfPopup.Show();
}
}
SchedulerViewModel.cs
private SchedulerAppointment appointment;
private DateTime selectedDate;
internal void UpdateEditor(SchedulerAppointment appointment, DateTime selectedDate)
{
this.appointment = appointment;
this.selectedDate = selectedDate;
if (this.appointment != null)
{
AppointmentEditorModel.Subject = this.appointment.Subject;
AppointmentEditorModel.Notes = this.appointment.Notes;
AppointmentEditorModel.StartDate = this.appointment.StartTime;
AppointmentEditorModel.EndDate = this.appointment.EndTime;
AppointmentEditorModel.IsEditorEnabled = true;
if (!this.appointment.IsAllDay)
{
AppointmentEditorModel.StartTime = new TimeSpan(this.appointment.StartTime.Hour, this.appointment.StartTime.Minute, this.appointment.StartTime.Second);
AppointmentEditorModel.EndTime = new TimeSpan(this.appointment.EndTime.Hour, this.appointment.EndTime.Minute, this.appointment.EndTime.Second);
AppointmentEditorModel.IsAllDay = false;
AppointmentEditorModel.IsEditorEnabled = true;
}
else
{
AppointmentEditorModel.StartTime = new TimeSpan(12, 0, 0);
AppointmentEditorModel.EndTime = new TimeSpan(12, 0, 0);
AppointmentEditorModel.IsEditorEnabled = false;
AppointmentEditorModel.IsAllDay = true;
}
}
else
{
AppointmentEditorModel.Subject = "";
AppointmentEditorModel.Notes = "";
AppointmentEditorModel.IsAllDay = false;
AppointmentEditorModel.StartDate = this.selectedDate;
AppointmentEditorModel.StartTime = new TimeSpan(this.selectedDate.Hour, this.selectedDate.Minute, this.selectedDate.Second);
AppointmentEditorModel.EndDate = this.selectedDate;
AppointmentEditorModel.EndTime = new TimeSpan(this.selectedDate.Hour + 1, this.selectedDate.Minute, this.selectedDate.Second);
}
}
After executing the previous code examples, we’ll get an output like in the following image.
Perform CRUD operations on SQLite database and update the .NET MAUI Scheduler
Let’s see how to perform CRUD actions on the SQLite database while synchronizing the changes with the .NET MAUI Scheduler control.
When you tap on the Scheduler, you can utilize the appointment editor pop-up to add, edit, and delete appointment details. On clicking the Save or Delete buttons in the appointment editor, both the Scheduler and SQLite database will be updated.
Saving an appointment
You can add appointments by providing the required details and clicking the Save button in the appointment editor. The following code examples illustrates the command associated with the Save button.
SchedulerViewModel.cs
public Command AddAppointment { get; set; }
AddAppointment = new Command(AddAppointmentDetails);
private void AddAppointmentDetails()
{
var endDate = AppointmentEditorModel.EndDate;
var startDate = AppointmentEditorModel.StartDate;
var endTime = AppointmentEditorModel.EndTime;
var startTime = AppointmentEditorModel.StartTime;
if (endDate < startDate)
{
Application.Current.MainPage.DisplayAlert("", "End date should be greater than start date", "OK");
}
else if (endDate == startDate)
{
if (endTime <= startTime)
{
Application.Current.MainPage.DisplayAlert("", "End time should be greater than start time", "OK");
}
else
{
AppointmentDetails();
}
}
else
{
AppointmentDetails();
}
}
private void AppointmentDetails()
{
if (appointment == null)
{
appointment = new SchedulerAppointment();
appointment.Subject = AppointmentEditorModel.Subject;
appointment.StartTime = AppointmentEditorModel.StartDate.Date.Add(AppointmentEditorModel.StartTime);
appointment.EndTime = AppointmentEditorModel.EndDate.Date.Add(AppointmentEditorModel.EndTime);
appointment.IsAllDay = AppointmentEditorModel.IsAllDay;
appointment.Notes = AppointmentEditorModel.Notes;
if (this.Appointments == null)
{
this.Appointments = new ObservableCollection<SchedulerAppointment>();
}
appointment.Id = Appointments.Count;
//// Add the appointments in the Scheduler.
Appointments.Add(appointment);
}
else
{
appointment.Subject = AppointmentEditorModel.Subject;
appointment.StartTime = AppointmentEditorModel.StartDate.Date.Add(AppointmentEditorModel.StartTime);
appointment.EndTime = AppointmentEditorModel.EndDate.Date.Add(AppointmentEditorModel.EndTime);
appointment.IsAllDay = AppointmentEditorModel.IsAllDay;
appointment.Notes = AppointmentEditorModel.Notes;
}
SaveSchedulerAppointmentAsync();
this.IsOpen = false;
}
The appointment details will be updated based on the user input, and the SaveSchedulerAppointmentAsync() method handles the addition or editing of appointments in both the Scheduler and the SQLite database.
Refer to the following code examples for saving an appointment in the SQLite database.
SchedulerViewModel.cs
private void SaveSchedulerAppointmentAsync()
{
//// - add or edit the appointment in the database collection.
var editAppointment = new Appointment()
{
From = appointment.StartTime,
To = appointment.EndTime,
AllDay = appointment.IsAllDay,
Notes = appointment.Notes,
EventName = appointment.Subject,
ID = (int)appointment.Id
};
App.Database.SaveSchedulerAppointmentAsync(editAppointment);
}
SchedulerDatabase.cs
//Insert an appointment in the database.
public int SaveSchedulerAppointmentAsync(Appointment appointment)
{
if (appointment == null)
{
throw new Exception("Null");
}
return _database.InsertOrReplace(appointment);
}
Deleting an appointment
By clicking the Delete button, we can delete an appointment in the .NET MAUI Scheduler and in the SQLite database. The following code examples demonstrate the command associated with the Delete button.
SchedulerViewModel.cs
public Command DeleteAppointment { get; set; }
DeleteAppointment = new Command(DeleteSchedulerAppointment);
private void DeleteSchedulerAppointment()
{
if (appointment == null)
{
this.IsOpen = false;
return;
}
//// Remove the appointments in the Scheduler.
Appointments.Remove(this.appointment);
//// Delete appointment in the database.
var deleteAppointment = new Appointment()
{
From = appointment.StartTime,
To = appointment.EndTime,
AllDay = appointment.IsAllDay,
Notes = appointment.Notes,
EventName = appointment.Subject,
ID = (int)appointment.Id
};
App.Database.DeleteSchedulerAppointmentAsync(deleteAppointment);
this.IsOpen = false;
}
SchedulerDatabase.cs
//Delete an appointment in the database.
public int DeleteSchedulerAppointmentAsync(Appointment appointment)
{
return _database.Delete(appointment);
}
After executing the previous code examples, we’ll get output like in the following image.
When rerunning the app, the .NET MAUI Scheduler will fetch the updated appointments from the SQLite database, and the output will be as follows.
GitHub reference
For more details, refer to the complete project on the GitHub repository.
Conclusion
Thanks for reading! In this blog, we learned how to load appointments in the .NET MAUI Scheduler with SQLite and perform effortless CRUD operations. Try out the steps discussed in this blog post and leave your feedback in the comments section below!
The newest version of Essential Studio is available for existing customers on the License and Downloads page. If you’re not a Syncfusion customer, sign up for our 30-day free trial to explore our features.
For questions, you can contact us through our support forum, support portal, or feedback portal. We are always happy to assist you!