Search This Blog

Tuesday, 30 June 2026

Local SQLite Database in .NET MAUI Complete CRUD Tutorial

Almost every mobile app needs to save data on the device – notes, settings, a cart, cached records. In .NET MAUI the easiest and most popular way to do this is with a local SQLite database. In this tutorial you will build a small Notes app and implement a complete CRUD (Create, Read, Update, Delete) workflow using the sqlite-net-pcl library.

What you will learn

  • How to add SQLite to a .NET MAUI project
  • How to create a model and a reusable database service
  • How to Insert, Read, Update and Delete records asynchronously
  • Where the database file lives on the device

Step 1 – Install the NuGet packages

Right‑click your project → Manage NuGet Packages and install:

  • sqlite-net-pcl – the ORM that lets you work with C# objects instead of raw SQL
  • SQLitePCLRaw.bundle_green – the native SQLite engine (usually pulled in automatically)
dotnet add package sqlite-net-pcl

Step 2 – Create the model

A model is just a plain C# class. The SQLite attributes tell the library how to build the table.

using SQLite;

namespace MauiSqliteDemo.Models;

public class Note
{
    [PrimaryKey, AutoIncrement]
    public int Id { get; set; }

    public string Title { get; set; } = string.Empty;

    public string Description { get; set; } = string.Empty;

    public DateTime CreatedAt { get; set; } = DateTime.Now;
}

Step 3 – Create the database service

This class opens the connection, creates the table on first use, and exposes async methods for every CRUD operation. Notice the lazy Init() pattern – the connection is only created once.

using SQLite;
using MauiSqliteDemo.Models;

namespace MauiSqliteDemo.Services;

public class NoteDatabase
{
    private SQLiteAsyncConnection _database;

    private async Task Init()
    {
        if (_database is not null)
            return;

        var dbPath = Path.Combine(FileSystem.AppDataDirectory, "notes.db3");
        _database = new SQLiteAsyncConnection(dbPath);
        await _database.CreateTableAsync<Note>();
    }

    // READ (all)
    public async Task<List<Note>> GetNotesAsync()
    {
        await Init();
        return await _database.Table<Note>().ToListAsync();
    }

    // READ (single)
    public async Task<Note> GetNoteAsync(int id)
    {
        await Init();
        return await _database.Table<Note>()
                              .Where(n => n.Id == id)
                              .FirstOrDefaultAsync();
    }

    // CREATE + UPDATE
    public async Task<int> SaveNoteAsync(Note note)
    {
        await Init();
        if (note.Id != 0)
            return await _database.UpdateAsync(note);   // existing record
        else
            return await _database.InsertAsync(note);   // new record
    }

    // DELETE
    public async Task<int> DeleteNoteAsync(Note note)
    {
        await Init();
        return await _database.DeleteAsync(note);
    }
}

Step 4 – Register the service (Dependency Injection)

Open MauiProgram.cs and register the database as a singleton so the whole app shares one instance.

builder.Services.AddSingleton<NoteDatabase>();

Step 5 – Use it in a page

Inject NoteDatabase through the page constructor and call the methods. Here is a quick example of every operation:

public partial class MainPage : ContentPage
{
    private readonly NoteDatabase _db;

    public MainPage(NoteDatabase db)
    {
        InitializeComponent();
        _db = db;
    }

    private async void OnSaveClicked(object sender, EventArgs e)
    {
        // CREATE
        var note = new Note { Title = "First note", Description = "Hello SQLite" };
        await _db.SaveNoteAsync(note);

        // READ
        List<Note> notes = await _db.GetNotesAsync();

        // UPDATE
        note.Title = "Updated title";
        await _db.SaveNoteAsync(note);

        // DELETE
        await _db.DeleteNoteAsync(note);
    }
}
Tip: FileSystem.AppDataDirectory points to a private folder for your app, so the database is safe and is not visible to the user or other apps.

Conclusion

You now have a fully working local database in .NET MAUI with clean, async CRUD methods. Because the service is registered with dependency injection, you can inject it into any page or view model.

Next, make your UI clean and testable by moving this logic into a view model – read MVVM in .NET MAUI with CommunityToolkit.Mvvm . Happy coding!

MVVM in .NET MAUI with CommunityToolkit.Mvvm

Writing all your logic in the code‑behind (the .xaml.cs file) quickly becomes messy and hard to test. The MVVM (Model‑View‑ViewModel) pattern fixes this by separating your UI from your logic. In this tutorial you will learn MVVM in .NET MAUI the modern way using CommunityToolkit.Mvvm, which removes almost all the boilerplate with source generators.

Why CommunityToolkit.Mvvm?

Traditionally you had to implement INotifyPropertyChanged, write full properties with backing fields, and create ICommand objects by hand. The toolkit generates all of that for you from simple attributes, so your view model stays tiny and readable.

Step 1 – Install the package

dotnet add package CommunityToolkit.Mvvm

Step 2 – Create the ViewModel

Two things are important: the class must be partial (so the generator can add code to it) and it should inherit from ObservableObject.

using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;

namespace MauiMvvmDemo.ViewModels;

public partial class MainViewModel : ObservableObject
{
    // Generates a public "Name" property with change notification
    [ObservableProperty]
    private string name = string.Empty;

    [ObservableProperty]
    private string greeting = string.Empty;

    // Generates a "GreetCommand" you can bind to a Button
    [RelayCommand]
    private void Greet()
    {
        Greeting = $"Hello, {Name}! Welcome to .NET MAUI MVVM.";
    }

    // Async commands are just as easy
    [RelayCommand]
    private async Task LoadAsync()
    {
        await Task.Delay(500); // simulate loading data
        Greeting = "Data loaded successfully.";
    }
}
How the magic works: the field name generates a property called Name, and the method Greet() generates a command called GreetCommand. Always bind to the generated PascalCase names.

Step 3 – Bind the View (XAML)

Set x:DataType for compiled bindings (faster and safer), then bind controls to the properties and commands.

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:vm="clr-namespace:MauiMvvmDemo.ViewModels"
             x:Class="MauiMvvmDemo.MainPage"
             x:DataType="vm:MainViewModel">

    <VerticalStackLayout Padding="20" Spacing="15">

        <Entry Placeholder="Enter your name"
               Text="{Binding Name}" />

        <Button Text="Greet"
                Command="{Binding GreetCommand}" />

        <Label Text="{Binding Greeting}"
               FontSize="18" />

    </VerticalStackLayout>
</ContentPage>

Step 4 – Connect the ViewModel with Dependency Injection

Register the page and the view model in MauiProgram.cs:

builder.Services.AddTransient<MainViewModel>();
builder.Services.AddTransient<MainPage>();

Then inject the view model into the page and set it as the BindingContext:

public partial class MainPage : ContentPage
{
    public MainPage(MainViewModel viewModel)
    {
        InitializeComponent();
        BindingContext = viewModel;
    }
}

Bonus – Enable/disable a button automatically

You can tell a command when it is allowed to run. The button is disabled automatically when the condition is false.

[RelayCommand(CanExecute = nameof(CanGreet))]
private void Greet() => Greeting = $"Hi {Name}!";

private bool CanGreet() => !string.IsNullOrWhiteSpace(Name);

// Re-check CanGreet whenever Name changes
[ObservableProperty]
[NotifyCanExecuteChangedFor(nameof(GreetCommand))]
private string name = string.Empty;

Conclusion

With CommunityToolkit.Mvvm you get clean, testable view models with almost no boilerplate. This is the recommended way to build .NET MAUI apps today.

Want to load real data into your view model? Check out “Consuming a REST API with HttpClient in .NET MAUI” and Local SQLite Database in .NET MAUI”.

Thursday, 13 October 2022

Implement Push Notification In .NET MAUI (iOS)

Creation Of Certificates & Profiles
Certificate 
Create Development Certificate In Your Apple Developer Account.


Once Certificated Created, Download it and Install In Your Mac (Double Tap On Downloaded Profile)

Identifiers (Bundle Identifier)
Create Bundle Identifier Of Your App.

Devices : Add Your Testing Device in Devices Section.

Profiles (Provisional Profile)
Create Development / Distribution Provisional Profile
Once Profile Created, Download it and Install In Your Mac (Double Tap On Downloaded Profile)


Keys:  Add APNs Key In Keys Option. Used for Push Notification
Create APNs Key and Download It and Save this file in some safe place. As You Can Only Download it once.

Adding App To Firebase Console
Create / Open Existing Project In Firebase Console.



Now Click On Add App Option and select iOS 


Now Click On Register app Option To Register App.


Now Download GoogleService-Info.plist file.

Now Select Project Setting Option from Project Overview.


Now Select Cloud Messaging Tab & Select Your Newly Created App.

Here You Need To Add APN Auth Key That You Created From Apple Developer Portal.

Click on Upload Button To Upload APNs Auth Key.

Add Key ID : You will find Key From Apple Developer Portal Keys Options.
Now Click On Keys that you have created you will find Key ID.

Add Team ID:  You Will Find Team ID from Membership Detail Tab of Apple Developer Account.


All Setup Is Ready Now Lets Implement that In .NET MAUI Project.
 

Implementing Push Notification In .NET MAUI Project

Create A New .NET MAUI Project With Sample Bundle Identifier that You had created 
In Apple Developer Account.

Or You Can Edit Existing Project Bunder Identifier (App Identifier)


Now Right Click On Your Project Dependencies/net7.0-ios or net 6.0-ios Option & Click On Manage NuGet Packages.



Now Install Xamarin.Firebase.iOS.CloudMessaging Plugin.


Now Add Following Code in Your AppDelegate.cs File of iOS Platform.

AppDelegate.cs
using Firebase.CloudMessaging;
using Firebase.Core;
using Foundation;
using PushNotificationDemoMAUI.Platforms.iOS;
using UIKit;
using UserNotifications;
 
namespace PushNotificationDemoMAUI;
 
[Register("AppDelegate")]
public class AppDelegate : MauiUIApplicationDelegate, IUNUserNotificationCenterDelegate, IMessagingDelegate
{
    public object completionhandler { get; private set; }
 
    protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
 
    public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions)
    {
 
        Firebase.Core.App.Configure(new Options("AddgoogleAppID","AddgcmSenderID")
        {
            ApiKey = "AddAPIKey",
            ClientId = "ClientID",
            BundleId = "com.companyname.pushnotificationdemomaui",
            ProjectId = "Your ProjectID"
        });
 
        //Adding GoogleService-Info.plist file and calling Firebase.Core.App.Configure() is not working
        // In .NET MAUI due to that I Manually Pass all Above Info.
        // Firebase.Core.App.Configure();
 
 
        if (UIDevice.CurrentDevice.CheckSystemVersion(10, 0))
        {
            // iOS 10 or later
            var authOptions = UNAuthorizationOptions.Alert | UNAuthorizationOptions.Badge | UNAuthorizationOptions.Sound;
            UNUserNotificationCenter.Current.RequestAuthorization(authOptions, (granted, error) =>
            {
                Console.WriteLine(granted);
            });
 
            // This Delete I used To Display Always Notification Even App Is Open
            UNUserNotificationCenter.Current.Delegate = new UserNotificationCenterDelegate();
 
            Messaging.SharedInstance.AutoInitEnabled = true;
            Messaging.SharedInstance.Delegate = this;
        }
        UIApplication.SharedApplication.RegisterForRemoteNotifications();
 
 
        return base.FinishedLaunching(application, launchOptions);
    }
 
    [Export("userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler:")]
    public  void DidReceiveRemoteNotification(UIApplication application, NSDictionary userInfo, Action<UIBackgroundFetchResult> completionHandler)
    {
        // Here Handle Notification Navigation WhenNotification Is REceived
    }
 
 
    [Export("messaging:didReceiveRegistrationToken:")]
    public void DidReceiveRegistrationToken(Messaging messaging, string fcmToken)
    {
        if (Preferences.ContainsKey("DeviceToken"))
        {
            Preferences.Remove("DeviceToken");
        }
        Preferences.Set("DeviceToken", fcmToken);
 
        App.Current.MainPage.DisplayAlert("Ok",fcmToken,"OK");
    }
}
 
GoogleAppID :  You Will Get From Project Setting / General Tab (Firebase Console)

GcmSenderID: You Will Get From the GoogleService-Info.plist File
ApiKey: You Will Get From the GoogleService-Info.plist File
Client ID :  You Will Get From the GoogleService-Info.plist File
BundleID : Your Project App Identifier
ProjectID:  You will get from the Project Setting / General Tab (Firebase Console)



UserNotificationCenterDelegate.cs
using UserNotifications;
 
namespace PushNotificationDemoMAUI.Platforms.iOS
{
    public class UserNotificationCenterDelegate : UNUserNotificationCenterDelegate
    {
        public UserNotificationCenterDelegate()
        {
        }
 
        public override void WillPresentNotification(UNUserNotificationCenter center, UNNotification notification,Action<UNNotificationPresentationOptions> completionHandler)
        {
            base.WillPresentNotification(center, notification, completionHandler);
 
            completionHandler(UNNotificationPresentationOptions.Alert);
        }
    }
}
 

Now Create  Entitlements.plist In Your Project Platforms/iOS 

In Entitlements.plist file Add aps-environment  as a key & development as a value.

Entitlements.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>aps-environment</key>
	<string>development</string>
</dict>
</plist>
 

Now All Setup Is Ready You can send push notification to device token.


Send Test Notification From Firebase Console.

Create New Campaign In Firebase Console.


Add Title & Message Then Click On Send test Message Button.


Now Add FCM Registration Token that is generated on First App Launch and Then Click on Test Button to send notification.














Saturday, 24 September 2022

Monday, 19 September 2022

Plugin.Maui.Popup

How to use Plugin.Maui.Popup 

Install Plugin.Maui.Popup Plugin in your project.

https://www.nuget.org/packages/Plugin.Maui.Popup   (1.0.4)








Now add xmlns:mauiPopup="clr-namespace:MauiPopup.Views;assembly=MauiPopup" this namespace in your content page.

Also replace ContentPage tag to <mauiPopup:BasePopupPage.

PopupPage.xaml
<?xml version="1.0" encoding="utf-8" ?>
<mauiPopup:BasePopupPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:mauiPopup="clr-namespace:MauiPopup.Views;assembly=MauiPopup"
             x:Class="MauiPopupDemo.PopupPage"
             Title="PopupPage">
    <VerticalStackLayout>
        <Label 
            Text="Welcome to .NET MAUI!"
            VerticalOptions="Center" 
            HorizontalOptions="Center" />
    </VerticalStackLayout>
</mauiPopup:BasePopupPage>
PopupPage.xaml.cs
using MauiPopup.Views;
namespace MauiPopupDemo;
public partial class PopupPage : BasePopupPage
{
	public PopupPage()
	{
		InitializeComponent();
	}
}


How to display Popup
MauiPopup.PopupAction.DisplayPopup(new PopupPage());
How to close Popup
MauiPopup.PopupAction.ClosePopup();

Display Popup that returning string value
string result = await MauiPopup.PopupAction.DisplayPopup(new PopupPage());
Now Pass String Value on ClosePopup Method
PopupAction.ClosePopup("hi");

Display Popup that returning other then string value
bool result = await MauiPopup.PopupAction.DisplayPopup<boo>(new PopupPage());
Now Pass Bool Value on ClosePopup Method
PopupAction.ClosePopup(true);


How to get value on popup close.

Pass Any Type of value in this method.
PopupAction.ClosePopup("hi");
To Get String Value
string result = await MauiPopup.PopupAction.DisplayPopup(new PopupPage());
To Get Other Type of Value
string result = await MauiPopup.PopupAction.DisplayPopup<int>(new PopupPage());
string result = await MauiPopup.PopupAction.DisplayPopup<bool>(new PopupPage());
string result = await MauiPopup.PopupAction.DisplayPopup<AnyTypeOfClass>(new PopupPage());

Implementation Video





Friday, 2 September 2022

Create Button Control With Progress Bar (Activity Indicator) In .NET MAUI / Xamarin

This video about creating Button Control With Progress Bar (Activity Indicator) In .NET MAUI / Xamarin. 
Disable Button On Click Until Activity Indicator IsRunning Property Set to False.

GitHub URL : https://github.com/mistrypragnesh40/ButtonControlWithProgressbar


Popular Posts