Share via

>Net Maui - Passing object between pages

John Rutherford 41 Reputation points
2025-04-18T06:06:56.33+00:00

I'm having trouble getting my DetailsPage to show the Observation obs object passed from my ResultsPage. I have a TapGestureRecognizer_Tapped method in the code behind the ResultsPage

private async void TapGestureRecognizer_Tapped(object sender, TappedEventArgs e)
{
    if (((VisualElement)sender).BindingContext is not Observation obs)
        return;
    var navigationParameter = new ShellNavigationQueryParameters
    {
        {"Observation", obs }
    };
    await Shell.Current.GoToAsync(nameof(DetailsPage), navigationParameter);
}

and on my DetailsPage ViewModel the following initialization code

using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using SunObs.Models;
using SunObs.Services;
namespace SunObs.ViewModel
{
    [QueryProperty(nameof(Observation), "Observation")]
    public partial class DetailsViewModel : BaseViewModel
    {
        [ObservableProperty]
        Observation obs;
        [ObservableProperty]
        [NotifyCanExecuteChangedFor(nameof(UpdateObservationAsyncCommand))]
        private bool calcDone;
        public IAsyncRelayCommand ComputeObsAsyncCommand { get; }
        public IAsyncRelayCommand UpdateObservationAsyncCommand { get; }
        readonly ObservationService _observationService;
        public DetailsViewModel(ObservationService observationService)
        {
            Title = "Edit Observation";
            _observationService = observationService;
            CalcDone = false;
            ComputeObsAsyncCommand = new AsyncRelayCommand(ComputeObsAsync);
            UpdateObservationAsyncCommand = new AsyncRelayCommand(UpdateObservationAsync);
        }

The details ContentPage has the following

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
            xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
            x:Class="SunObs.Views.DetailsPage"
            xmlns:converters="clr-namespace:SunObs.Converters"
            xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
            xmlns:local="clr-namespace:SunObs.Models"
            xmlns:model="clr-namespace:SunObs.Models"
            xmlns:viewmodel="clr-namespace:SunObs.ViewModel"
            x:DataType="viewmodel:DetailsViewModel"
            Title="{Binding Obs.Id, StringFormat='Edit Observation : {0}'}">
    <ContentPage.Resources>
        <converters:AngleConverter x:Key="AngConv"/>
    </ContentPage.Resources>
    <Shell.BackButtonBehavior>
        <BackButtonBehavior IsEnabled="False"/>
    </Shell.BackButtonBehavior>
    <VerticalStackLayout BackgroundColor="Transparent" Spacing="10" Margin="10,10,10,0">
        <Grid RowDefinitions="Auto, Auto, Auto, Auto, Auto, Auto, Auto, Auto, Auto, Auto, Auto, Auto, Auto, Auto, Auto, Auto, Auto, Auto"
          ColumnDefinitions="Auto,*" RowSpacing="5" ColumnSpacing="5" Margin="8">
            
            <Border Grid.Row="2" Grid.Column="0" Style="{StaticResource borderinput}">
                <Label Style="{StaticResource lbl}" Text="Observation Date"/>
            </Border>
            <DatePicker Grid.Row="2" Grid.Column="1"
                        x:Name="DPicker" Date="{Binding Obs.ObsDate}"
                        VerticalOptions="Center" 
                        DatePicker.Format="dd-MMM-yyyy"/>
            
            <Border Grid.Row="3" Grid.Column="0" Style="{StaticResource borderinput}">
                <Label Style="{StaticResource lbl}" Text="Watch Time"/>
            </Border>
            <Entry Placeholder="00:00:00" PlaceholderColor="Blue"
                    x:Name="WT" Text="{Binding Obs.WT}"
                    VerticalOptions="Center"
                    Grid.Row="3" Grid.Column="1">
                <Entry.Behaviors>
                    <toolkit:SelectAllTextBehavior />
                </Entry.Behaviors>
            </Entry>

to bind the Observation object obs along with all the other properties needed.

However, when the page displays, all the properties are set to zero. I've watched many videos and read the documentation. Can you please show me how to pass the object correctly.

TIA

Developer technologies | .NET | .NET MAUI
0 comments No comments

Answer accepted by question author
  1. Michael Le (WICLOUD CORPORATION) 11,235 Reputation points Microsoft External Staff Moderator
    2025-07-25T04:59:04.2+00:00

    Hello,

    I know you've already solved the issue, but I wanted to provide some information that might be helpful for others facing similar problems

    Shell navigation in .NET MAUI serializes all parameters as URI strings for the underlying navigation system. When complex objects (non-primitive types) are passed via ShellNavigationQueryParameters, the framework attempts to convert them to string representations, which often results in:

    • Loss of object data
    • Default property values (nulls, zeros)
    • Silent failures without error messages

    Recommended Solution

    Use a shared static service or singleton to store the object before navigation. Here's how:

    1. Create a static data service

    public static class NavigationDataStore
    {
        public static Observation CurrentObservation { get; set; }
    }
    

    2. Set the object before navigating

    private async void TapGestureRecognizer_Tapped(object sender, TappedEventArgs e)
    {
        if (((VisualElement)sender).BindingContext is not Observation obs)
            return;
     
        NavigationDataStore.CurrentObservation = obs;
        await Shell.Current.GoToAsync(nameof(DetailsPage));
    }
    

    3. Retrieve the object in the DetailsViewModel

    public DetailsViewModel(ObservationService observationService)
    {
        Title = "Edit Observation";
        _observationService = observationService;
        Obs = NavigationDataStore.CurrentObservation;
        CalcDone = false;
        ComputeObsAsyncCommand = new AsyncRelayCommand(ComputeObsAsync);
        UpdateObservationAsyncCommand = new AsyncRelayCommand(UpdateObservationAsync);
    }
    

    Alternative

    If you need to persist data across sessions or support deep linking, consider serializing the object to JSON and passing it as a string, then deserializing it on the target page. However, this only works if the object is serializable and the data size is small.

    I hope this helps clarify the issue.

    References:

    1 person found this answer helpful.

1 additional answer

Sort by: Most helpful
  1. John Rutherford 41 Reputation points
    2025-04-19T03:05:52.2066667+00:00

    Solved it myself.

    0 comments No comments

Your answer

Answers can be marked as 'Accepted' by the question author and 'Recommended' by moderators, which helps users know the answer solved the author's problem.