Xamarin Forms – Integrating Firebase Database and Performing CRUD Operations

  • by
xamarin-forms-firebase-database-app-tutorial-002

In this tutorial, we will integrate Google’s Firebase Realtime Database into our Xamarin Forms app and perform Create, Read, Update & Delete (CRUD) operations from the app. The app contains a simple ListView which will display product information from the firebase database and some more controls to save product informations on the cloud database. So let’s begin. DOWNLOAD SOURCE CODE

We will use Xamarin Forms MVVM design pattern to create the application, so I expect you to have a good knowledge of xamarin forms and MVVM architecture. Though this particular app is pretty simple and easy to understand.

Creating the Project in Firebase:

Head on to the Google Firebase developer console and follow this steps to create your app on it.

1. Create project – Give your project a nice name

firebase-database-create-project-001

2. Select your Google Analytics preferences and select the account to use with your DB:

firebase-database-google-analytics

firebase-database-select-account

3. Your project will start to create.

firebase-database-creating-project

 

4. Once you are on your dashboard, select “Realtime Database” and press on “Create Database”

firebase-database-create-database

5. Select your preferred region (I selected United States (us-central1)) and security rules as Test mode

firebase-database-select-security-modes

6. Project URL: Once you are able to access your database, copy your database URL. We will use it in a bit.

firebase-database-project-url

Xamarin MVVM Project:

In your xamarin forms project install two nuget packages:

  1. FirebaseDatabase.net
  2. Newtonsoft.Json

Create three folders with names Views, Models, ViewModels like below. Don’t create the classes and files yet. We will create it step-by-step.xamarin-forms-firebase-project-structure

Inside the Views folder, create a new Content Page with name AddProducts.xaml and edit it as below:

Views > AddProducts.xaml:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamFirebase.Views.AddProducts"
Title="Xamarin Firebase DB"
Visual="Material"
NavigationPage.HasNavigationBar="True"
BackgroundColor="White">
<ContentPage.Content>

<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="3*"/>
<RowDefinition Height="6*"/>
</Grid.RowDefinitions>
<StackLayout Orientation="Vertical" Grid.Row="0" Padding="5" Spacing="5">
<Entry x:Name="txtProductName" Placeholder="Enter Product Name" Text="{Binding product.productName}"
HorizontalOptions="FillAndExpand"/>
<Entry x:Name="txtPrice" Placeholder="Enter Product Price" Text="{Binding product.productPrice}"
HorizontalOptions="FillAndExpand" Keyboard="Numeric"/>

<Button x:Name="btnSave" Text="{Binding btnSaveText}"
Command="{Binding btnSaveProduct}" IsVisible="{Binding showButton}"/>

<ActivityIndicator x:Name="activityIndicator1" IsVisible="{Binding isBusy}"
IsRunning="{Binding isBusy}"/>

<Label FontSize="Micro" x:Name="lblMessage" Text="{Binding lblMessage}" HorizontalOptions="FillAndExpand"/>
</StackLayout>

<StackLayout Orientation="Vertical" Grid.Row="1" VerticalOptions="FillAndExpand">
<StackLayout Orientation="Horizontal" HorizontalOptions="FillAndExpand" VerticalOptions="Start" Padding="5"
BackgroundColor="#c9c9c9">

<Label Text="Name" WidthRequest="300" TextColor="#000" FontAttributes="Bold"
VerticalOptions="Start"/>
<Label Text="Price" WidthRequest="100" TextColor="#fc0339" FontAttributes="Bold"
VerticalOptions="Start"/>
</StackLayout>

<ListView x:Name="lstProducts" ItemsSource="{Binding lstProducts}"
HorizontalOptions="FillAndExpand" VerticalOptions="Start" SeparatorColor="Black"
CachingStrategy="RecycleElement" ItemSelected="lstProducts_ItemSelected">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal" HorizontalOptions="FillAndExpand"
VerticalOptions="Start" Padding="5" BackgroundColor="#fff">
<Label Text="{Binding productName}" WidthRequest="300" TextColor="#000"
FontAttributes="Bold" VerticalOptions="Start"/>
<Label Text="{Binding productPrice}" WidthRequest="100" TextColor="#fc0339"
FontAttributes="Bold" VerticalOptions="Start"/>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</Grid>

</ContentPage.Content>
</ContentPage>

This is our main layout page. This app will contain only one form as for now i.e. adding, updating, deleting and viewing the products in Firebase database will be done using this form.

xamarin-forms-firebase-database-app-tutorial

Now edit its code-behind code as below:

Views > AddProducts.xaml.cs:

using System;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
using XamFirebase.Models;
using XamFirebase.ViewModels;

namespace XamFirebase.Views
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class AddProducts : ContentPage
{
VMProducts vmProduct;
public AddProducts()
{
InitializeComponent();
vmProduct = new VMProducts();
this.BindingContext = vmProduct;
}

private async void lstProducts_ItemSelected(object sender, SelectedItemChangedEventArgs e)
{
try
{
if (lstProducts.SelectedItem != null)
{
Products product = (Products)e.SelectedItem;
if (product != null)
{
var display = await DisplayActionSheet(product.productName, "Cancel",
null, new string[] { "Edit", "Delete" });
if (display.Equals("Edit"))
{
vmProduct.setProduct(product);
}
else if (display.Equals("Delete"))
{
vmProduct.setProduct(product);
await vmProduct.trnProducts("DELETE");
}
}
}
}
catch (Exception ex)
{
}
lstProducts.SelectedItem = null;
}
}
}

As you can see, we are using a class file named VMProducts as BindingContext of this form. This class needs to be created inside ViewModels folder. Here we are also passing the selected item from the listview to our ViewModel method setProduct. When a user selects an item from the listview, an ActionSheet is displayed wherein options for Edit or Deleting the product is shown. For both the scenarios ViewModel will be called to take respective actions.

Create a class file inside ViewModel folder with name VMProducts.cs and edit it as below:

ViewModels> VMProducts.cs:

using Firebase.Database;
using Newtonsoft.Json;
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using System.Windows.Input;
using Xamarin.Forms;
using XamFirebase.Models;

namespace XamFirebase.ViewModels
{
public class VMProducts : INotifyPropertyChanged
{
FirebaseClient fClient;

private Products _product { get; set; }

public Products product
{
get { return _product; }
set
{
_product = value;
OnPropertyChanged();
}
}

private bool _showButton { get; set; }
public bool showButton
{
get { return _showButton; }
set
{
_showButton = value;
OnPropertyChanged();
}
}
private bool _isBusy { get; set; }
public bool isBusy
{
get { return _isBusy; }
set
{
_isBusy = value;
OnPropertyChanged();
showButton = !value;
}
}

private ICommand _btnSaveProduct { get; set; }
public ICommand btnSaveProduct
{
get { return _btnSaveProduct; }
set
{
_btnSaveProduct = value;
OnPropertyChanged();
}
}

private string _lblMessage { get; set; }
public string lblMessage
{
get { return _lblMessage; }
set
{
_lblMessage = value;
OnPropertyChanged();
}
}

private ObservableCollection<Products> _lstProducts { get; set; }

public ObservableCollection<Products> lstProducts
{
get { return _lstProducts; }
set
{
_lstProducts = value;
OnPropertyChanged();
}
}

private string _btnSaveText { get; set; }
public string btnSaveText
{
get { return _btnSaveText; }
set
{
_btnSaveText = value;
OnPropertyChanged();
}
}

readonly string productResource = "Products";
public VMProducts()
{
try
{
lstProducts = new ObservableCollection<Products>();
btnSaveProduct = new Command(async () =>
{
isBusy = true;
await trnProducts("ADD");
});
var callList = new Command(async () => await GetAllProducts());
callList.Execute(null);

}
catch (Exception ex)
{
lblMessage = "Error occurred " + ex.Message.ToString();
}
}

public bool connectFirebase()
{
try
{
if (fClient == null)
fClient = new FirebaseClient("https://xamarinformsproject-default-rtdb.firebaseio.com/");
return true;
}
catch (Exception ex)
{
lblMessage = "Error occurred in connecting firebase. Error:" + ex.Message.ToString();
return false;
}

}

public async Task trnProducts(string action)
{
try
{
if (product == null || String.IsNullOrWhiteSpace(product.productName) || product.productPrice == null)
{
lblMessage = "Please enter product details to save product";
isBusy = false;
return;
}

if (connectFirebase())
{
Products products = new Products();
products.productName = product.productName;
products.productPrice = product.productPrice;
if (btnSaveText == "SAVE" && action.Equals("ADD"))
{
products.productId = Guid.NewGuid();

await fClient.Child(productResource).PostAsync(JsonConvert.SerializeObject(products));
await GetAllProducts();
lblMessage = "Product saved successfully";
}
else if (btnSaveText == "UPDATE" && action.Equals("ADD"))
{
products.productId = product.productId;

var updateProduct = (await fClient.Child(productResource).OnceAsync<Products>()).FirstOrDefault(x => x.Object.productId == products.productId);

if (updateProduct == null)
{
lblMessage = "Cannot find selected Product";
isBusy = false;
return;
}
await fClient
.Child(productResource + "/" + updateProduct.Key).PatchAsync(JsonConvert.SerializeObject(products));
await GetAllProducts();
lblMessage = "Product updated successfully";
}
else if (action.Equals("DELETE"))
{
var deleteProduct = (await fClient
.Child(productResource)
.OnceAsync<Products>()).FirstOrDefault(d => d.Object.productId == product.productId);

if (deleteProduct == null)
{
lblMessage = "Cannot find selected Product";
isBusy = false;
return;
}

await fClient
.Child(productResource + "/" + deleteProduct.Key).DeleteAsync();

await GetAllProducts();
lblMessage = "Product delete successfully";
}

}
}
catch (Exception ex)
{
lblMessage = "Error occurred. Cannot save Product. Error:" + ex.Message.ToString();

}
isBusy = false;
}

public async Task GetAllProducts()
{
Clear();
isBusy = true;
try
{
lstProducts = new ObservableCollection<Products>();
if (connectFirebase())
{
var lst = (await fClient.Child(productResource).OnceAsync<Products>()).Select(x =>
new Products
{
productId = x.Object.productId,
productName = x.Object.productName,
productPrice = x.Object.productPrice,
}).ToList();

lstProducts = new ObservableCollection<Products>(lst);
}
}
catch (Exception ex)
{
lblMessage = "Error occurred in getting products. Error:" + ex.Message.ToString();
}
isBusy = false;
}

public void setProduct(Products edt)
{
product = new Products();
product.productName = edt.productName;
product.productPrice = edt.productPrice;
btnSaveText = "UPDATE";
product.productId = edt.productId;
}

public void Clear()
{
product = new Products();
product.productName = "";
product.productPrice = null;
isBusy = false;
product.productId = Guid.Empty;
btnSaveText = "SAVE";
lblMessage = "";
}

#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
var changed = PropertyChanged;
if (changed == null)
return;

changed.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
}

Create a new class inside Models folder with name Products.cs and edit it as below:

Models > Products.cs:

using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;

namespace XamFirebase.Models
{
public class Products : INotifyPropertyChanged
{
private Guid _productId { get; set; }

public Guid productId
{
get { return _productId; }
set
{
_productId = value; OnPropertyChanged();
}
}
private string _productName { get; set; }

public string productName
{
get { return _productName; }
set
{
_productName = value; OnPropertyChanged();
}
}
private double? _productPrice { get; set; }

public double? productPrice
{
get { return _productPrice; }
set
{
_productPrice = value; OnPropertyChanged();
}
}

#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
var changed = PropertyChanged;
if (changed == null)
return;

changed.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
}

This class is our main model class which is used in both the ViewModel class as well as on the View. Now change the start page of your app to AddProducts page in App.xaml.cs class:

App.xaml.cs:

using System;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;

namespace XamFirebase
{
public partial class App : Application
{
public App()
{
InitializeComponent();

MainPage = new NavigationPage(new Views.AddProducts());
}

protected override void OnStart()
{
}

protected override void OnSleep()
{
}

protected override void OnResume()
{
}
}
}

Additionally you can add this design code to your App.xaml file:
App.xaml:

<?xml version="1.0" encoding="utf-8" ?>
<Application xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamFirebase.App">
<Application.Resources>

<ResourceDictionary>
<Style TargetType="Entry">
<Setter Property="BackgroundColor" Value="#f5f5f5"/>
<Setter Property="TextColor" Value="#000"/>
<Setter Property="PlaceholderColor" Value="#787878"/>
</Style>

<Style TargetType="Button">
<Setter Property="BackgroundColor" Value="#1976D2"/>
<Setter Property="TextColor" Value="#fff"/>
</Style>

<Style TargetType="Label">
<Setter Property="TextColor" Value="#000"/>
<Setter Property="FontSize" Value="Default"/>
<Setter Property="BackgroundColor" Value="Transparent"/>
</Style>
</ResourceDictionary>
</Application.Resources>
</Application>

Run the app now:

xamarin-forms-firebase-database-app-tutorial-002

DOWNLOAD SOURCE CODE

Also see:

Xamarin Forms – Get current Location along with Latitude and Longitude

Xamarin forms Creating Action Sheets

Xamarin forms MVVM Binding CommandParameter to Command

Xamarin forms SQLite database – Performing CRUD operations

Xamarin forms creating and using SQLite database

Xamarin forms using Google Maps

Xamarin forms using Camera – saving Images to Gallery

Xamarin Forms Creating a Simple ListView

Xamarin Forms MVVM ListView ItemSource Binding

Xamarin forms Create HTML formatted Label