Reputation: 17
In my .NET MAUI mobile app (targeted device: Android) which I am developing using the MVVM pattern, when performing some navigation from the home page to sub-pages in order to go back from a certain sub-page to the home I tap on the default go back arrow icon that appears on the top bar of the screen.
My assumption is that doing so does not "destroy"/remove the page/view and the viewmodel associtaed to it and this assumption comes from the fact that in the constructor of my viewmodel I call an API endpoint throught HttpClient this does simply inserts a record in my SQL Server DB, when It's the first time I am on that page the record inserted in the DB is 1 but if I go back (using that default arrow icon at the top) and then return to that same page/view and the function is executed again (note that this function is inside the viewmodel constructor) the same record is inserted twice in the DB.
Same goes for the DisplayAlert method (again all the alerts are in the viewmodel constructor) if it is my 1st time on that page the alert is displayed once but if I go back and then return the number of times the apps shows the alert gets incremented by 1.
This is the routes registrations in AppShell:
public AppShell()
{
InitializeComponent();
Routing.RegisterRoute(nameof(Warehouse), typeof(Warehouse));
}
This is the code-behind of the view:
public partial class Warehouse: ContentPage
{
private WarehouseViewModel ICvm;
public Warehouse()
{
InitializeComponent();
ICvm = new WarehouseViewModel();
BindingContext = ICvm;
}
}
This is how from the Homepage I perform navigation executing a command when a button is tapped:
await Shell.Current.GoToAsync(nameof(Warehouse));
And this is the viewmodel:
internal class WarehouseViewModel: INotifyPropertyChanged
{
public WarehouseViewModel()
{
MessagingCenter.Subscribe<object, string>(this, "ScannedBarcodeFromMainActivity", async (sender, ScannedBarcode) =>
{
ScannedBarcodeReceived = ScannedBarcode;
bool Insertion_To_DB_Outcome = await MyApiService.Set_PC(ScannedBarcodeReceived);
if (!Insertion_To_DB_Outcome)
{
await App.Current.MainPage.DisplayAlert("Error while inserting", "error while inserting to db :(", "OK");
}
else
{
await App.Current.MainPage.DisplayAlert("Success","Success inserting to db", "OK");
}
});
}
}
What I actually want is that when I press the default back button (standard arrow icon at top) the page/view and the related viewmodel gets resetted so both the insertion in DB and the alert are executed only once.
Upvotes: 0
Views: 2058
Reputation: 464
The first thing to check : in your MauiProgram.cs, do you declare your ViewModel as Singleton (builder.Services.AddSingleton<WarehouseViewModel>
) or Transient (builder.Services.AddTransient<WarehouseViewModel>
) ? A Singleton ViewModel isn't reset when you reload the View, only a single Instance of the ViewModel is used, when a Transient is regenerated every time.
In case you need to keep your ViewModel as a Singleton, the key is to define a custom Back Button command in your ContentPage :
<Shell.BackButtonBehavior>
<BackButtonBehavior x:DataType="YourViewModel" Command="{Binding BackButtonPressedCommand}"/>
</Shell.BackButtonBehavior>
Edit : didn't see your page was not a xaml page. I didn't test it yet, but in that case you might want to try this in your page Constructor after setting your BindingContext :
this.BackButton.Command = YourViewModel.BackButtonPressedCommand;
In your viewmodel (I did it using MVVM CommunityToolkit, you can find more informations about generic Commands here) :
[RelayCommand]
public void BackButtonPressed()
{
// ... Your custom back button behavior, reset the page/view/viemwmodel
Shell.Current.GoToAsync("..");
}
Upvotes: 1