Easily Load Appointments in .NET MAUI Scheduler with SQLite and Perform CRUD
Detailed Blog page Skeleton loader
Easily Load Appointments in .NET MAUI Scheduler with SQLite and Perform CRUD

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:

Let’s get started!

Note: Before proceeding, see the getting started with .NET MAUI Scheduler documentation.

Easily build cross-platform mobile and desktop apps with the flexible and feature-rich controls of the Syncfusion .NET MAUI platform.

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.

Install sqlite-net-pcl NuGet package

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 SchedulerDatabase(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.

Populating appointments from SQLite database to .NET MAUI Scheduler
Populating appointments from SQLite database to .NET MAUI Scheduler

Syncfusion .NET MAUI controls are well-documented, which helps to quickly get started and migrate your Xamarin apps.

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.

Schedule appointment editor
Schedule appointment editor

To make it easy for developers to include Syncfusion .NET MAUI controls in their projects, we have shared some working ones.

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.

Performing CRUD operations in SQLite database using .NET MAUI Scheduler
Performing CRUD operations in SQLite database using .NET MAUI Scheduler

When rerunning the app, the .NET MAUI Scheduler will fetch the updated appointments from the SQLite database, and the output will be as follows.

Updating the .NET MAUI Scheduler appointments loaded from SQLite database
Updating the .NET MAUI Scheduler appointments loaded from SQLite database

GitHub reference

For more details, refer to the complete project on the GitHub repository.

Supercharge your cross-platform apps with Syncfusion's robust .NET MAUI controls.

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 forumsupport portal, or feedback portal. We are always happy to assist you!

Related blogs

Be the first to get updates

Jeyasri Murugan

Meet the Author

Jeyasri Murugan

I'm Jeyasri Murugan, a Product Manager at Syncfusion. I have experience in developing custom controls for various .NET frameworks, including .NET MAUI, Xamarin, WPF, WinUI, and UWP.

Comments (2)

Hello thank you for this project and all of your products !

Just a small observation if you don’t mind

private void Scheduler_Tapped(object sender, SchedulerTappedEventArgs e)
{
if (e.Element == SchedulerElement.Header) return;

in MainPage.xaml.cs it will stop popup appearing when you change view.

Can you add data to the Scheduler asynchronously ?
I cannot seem to figure out how – I have Async Database and Async Rest Services to feed data in

Am I missing something ?

Thank you once more

Hi Richard,

Thank you for sharing the information about preventing the pop-up from appearing when changing the scheduler view. We have updated the blog sample accordingly.

Regarding loading data asynchronously in the scheduler, it is possible. You can fetch the data from a JSON source or database and then map it to the scheduler appointments. For a detailed example, please refer to our blog post: https://www.syncfusion.com/blogs/post/on-demand-loading-web-service-dotnet-maui

Comments are closed.