How to transfer data from one page to another in .NET MAUI or Xamarin Forms ?

Coding Confidence: Mastering Seamless Data Transfer Between Pages in .NET MAUI and Xamarin Forms

Himanshu Tyagi
5 min readDec 12, 2023

Introduction:

In the development of Xamarin and .NET MAUI mobile app development, one challenge for developers involves the seamless transfer of data between pages. This article talks about a problem and explains why the usual methods don’t work well. We’ll also look at a solution to help developers overcome these problems and make sharing data in their projects better.

Problem:

In mobile app development, a common problem is moving data from one page to another. For example, if an app shows a list of employees on the home page and you need to display more details about a chosen employee on the next page, the usual method involves using parameters in constructors for data transfer. However, this can be problematic as it tightly connects the pages. This article aims to solve this issue and offer an improved solution.

Solution:

To avoid the complexities of pages being tightly coupled, we suggest combining Model-View-ViewModel (MVVM) architecture with Dependency Injection (DI). By using a special service layer to hold data temporarily, we create a setup where data transfer is smooth. Although we mainly focus on .NET MAUI in this discussion, the solution we propose also works well with older Xamarin Forms. Let’s go through the steps to apply this method and see how it makes the code more flexible and easy to maintain.

Step 1: Create a New Project

Create a new project in .NET MAUI, lets name our project “DataSharingSample”.

Step 2: Structure Solution

Let’s add some folders in the shared code:

· Abstract

· Helper

· Models

· Services

· ViewModels

· Views

After you’ve added these folders, your solution will appear similar to the image below:

Folders like Abstract, Helper, Models, Services, ViewModels, and Views are added to the shared code for better organization. The Abstract folder typically contains interfaces, the Helper folder contains utility classes, Models hold data structures, Services encapsulate business logic, ViewModels handle presentation logic, and Views represent the UI components.

Step 3: Add Code to Illustrate the Problem

Let’s include some code to show the problem. I made two pages, HomePage and DetailPage, along with ViewModels and an Employee Model class. There’s a file called ServiceHelper under Helper, needed for Dependency Injection (DI). After doing all this, the solution will appear similar to the image below:

Step 4: Create an Interface

Now, create an interface under Abstract called “ISharedService” and include the code provided below:

using System;
namespace DataSharingSample.Abstract
{
public interface ISharedService
{
void Add<T>(string key, T value) where T : class;
T GetValue<T>(string key) where T : class;
}
}

Step 5: Implement the Service

Now, in the Services folder, add a class named "SharedService" that will implement the interface and include the code provided below:

using System;
using DataSharingSample.Abstract;
namespace DataSharingSample.Services
{
public class SharedService : ISharedService
{
private Dictionary<string, object> DTODict { get; set; } = new Dictionary<string, object>();
public void Add<T>(string key, T value) where T : class
{
if (DTODict.ContainsKey(key))
{
DTODict[key] = value;
}
else
{
DTODict.Add(key, value);
}
}
public T GetValue<T>(string key) where T : class
{
if (DTODict.ContainsKey(key))
{
return DTODict[key] as T;
}
return null;
}
}
}

Here, a dictionary named DTODict is created within the “SharedService” class to store data in key-value pairs. The Add method is used to add or update data in the dictionary, and the GetValue method is used to retrieve data based on the provided key. The dictionary acts as a storage mechanism for shared data. The implementation follows the contract outlined by the ISharedService interface, allowing for loose coupling and separation of the data-sharing mechanism from the rest of the application.

Step 6: Connect the Interface with Dependency Injection

Now, add ViewModels and connect the interface ISharedService with the class SharedService. Make the code changes as provided below in “MauiProgram.cs”:

using DataSharingSample.Abstract;
using DataSharingSample.Services;
using DataSharingSample.ViewModels;
using Microsoft.Extensions.Logging;

namespace DataSharingSample;
public static class MauiProgram
{
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder
.UseMauiApp<App>()
.ConfigureFonts(fonts =>
{
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
});

builder.Services.AddTransient<HomePageViewModel>();
builder.Services.AddTransient<DetailPageViewModel>();
builder.Services.AddSingleton<ISharedService, SharedService>();

#if DEBUG
builder.Logging.AddDebug();
#endif

return builder.Build();
}
}

Changes in “MauiProgram.cs” involve configuring the app’s services, including adding transient services for the view models and a singleton service for ISharedService. This establishes the necessary infrastructure for Dependency Injection.

Step 7: Use the SharedService in HomePageViewModel

Let’s use the same, perform the code changes as given below in “HomePageViewModel” :

 private void NavigatedToEmployeeDetails(Employee employee)
{
try
{
if (employee is null)
{
return;
}
_SharedService.Add<Employee>("SelectedEmployee", employee);
MainThread.BeginInvokeOnMainThread(async () => { await App.Current.MainPage.Navigation.PushAsync(new DetailPage(), true); });
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}

Here we are adding the employee object into our SharedService, this will be fetched on the next page.

The code in “HomePageViewModel” adds the selected employee to the SharedService, ensuring that the data is available for retrieval on the next page. The use of MainThread.BeginInvokeOnMainThread ensures safe execution on the UI thread.

Step 8: Retrieve Data in DetailPageViewModel

Now, let's retrieve employee data by making the following code changes in "DetailPageViewModel":

public class DetailPageViewModel : BaseViewModel
{
private Employee selectedEmployee;
public Employee SelectedEmployee
{
get => selectedEmployee;
set
{
selectedEmployee = value;
OnPropertyChanged("SelectedEmployee");
}
}

ISharedService _SharedService;

public DetailPageViewModel(ISharedService sharedService)
{
try
{
_SharedService = sharedService;
GetSelectedEmployee();
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}

private void GetSelectedEmployee()
{
try
{
SelectedEmployee = _SharedService.GetValue<Employee>("SelectedEmployee");
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
}

In this “DetailPageViewModel,” we fetch the selected employee data from the SharedService using the GetSelectedEmployee method. This ensures that the data is available for use on the detail page. Any potential exceptions are caught and logged.

Code:

Explore the complete code and dive deeper into the details! Check out the GitHub repository for this project. Happy coding!

https://github.com/thimanshu1993/MauiDataSharing

Conclusion:
Sharing data between pages doesn’t have to be a headache. By combining MVVM and DI, we’ve shown that there’s a better way. This approach not only solves the immediate problem but also sets up a foundation for a more flexible and easy-to-maintain app. Whether you’re starting a new .NET MAUI project or working on an older Xamarin Forms app, this method ensures that sharing data becomes a breeze, making your development journey smoother.

© 2023. All Rights Reserved.

--

--

Himanshu Tyagi

Technical Lead || Passionate About : NET MAUI, Xamarin Forms, Mobile App Architecture, Open Source Contribution, Continuous Learning in the Tech Space