Prism: [Bug][Forms] Initialize & OnNavigatedTo not called on Region's ViewModel

Created on 18 Feb 2021  ·  6Comments  ·  Source: PrismLibrary/Prism

Description

  • Using the new region concept for xamarin forms, when navigating to a given region, Initialize and OnNavigatedToare not called in the Region's ViewModel.

Steps to Reproduce

  1. Implement Initialize& OnNavigatedToon VM ( i.e IInitialize& INavigationAware)
  2. Add region to xaml, register it, and navigate to it
  3. Notice the constructor of the region's VM is effectively called but OnInitialize& OnNavigatedToare never being called (put breakpoints or just check console output)

Expected Behavior

  • Initialize& OnNavigatedToshould be called.

Actual Behavior

  • Not called

Basic Information

  • Version with issue: 8.0.0.1909
  • Last known good version: x
  • Xamarin.Forms version: 5.0.0.1874
  • IDE: VS 16.8.4

Reproduction Link

RegionInitialize.zip

I also just checked out this project https://github.com/Nobody84/Prototype.XF.Prism.RegionNavigation , changed Unity to Dryloc to fix IActiveRegion registration issue, added Initialize & OnNavigated, there are also not called.

bug to verify

Most helpful comment

The IRegionAware interface has a slightly different set of methods as theyre passing INavigationContext which contains what you'd expect, INavigationParameters. No IInitialize which is annyoing.

What I ended up doing in my app was further separating my base view models:

  • ViewModelBase
  • PageViewModel
  • RegionViewModel

ViewModelBase inherits BindableBase and implements IDestructible. I'm passing things like INavigationService as well as my logging implementation. This doesn't have any of the lifecycle code in it.

PageViewModel inherits ViewModelBase which implements IInitialize, IInitializeAsync, INavigationAware, all of my pages use this base class

RegionViewMode inherits ViewModelBase and implements IRegionAware, IRegionMemberLifetime, all of my regions use this base class. I added the following code to give myself an experience similar to IInitialise, its definitely a cringe implementation but 🤷‍♂️

private bool _initialized = false;

public virtual void OnNavigatedTo(INavigationContext navigationContext)
{
    if (!_initialized)
    {
        _initialized = true;

        Initialize(navigationContext.Parameters);
    }
}

protected virtual void Initialize(INavigationParameters navigationParameters) { }

A bit hacky but now I can override Initialize in my region view model and run whatever startup code I need to without constantly having to guard for that behaviour in a region view model.

In response to your question of when to use INavigationAware and when to use IRegionAware:

  • Use INavigationAware when navigating between pages
  • Use IRegionAware when navigating between regions

All 6 comments

Have you used the interface IRegionAware? that is the interface you need to use for region navigation 😁

Oh right. I tried this and indeed it works, I hit OnNavigatedTo. Thank you, that could be at least a workaround for now.

Prob is OnNavigatedTois not exactly the same as Initialize exposed by IInitialize.

From what I see here : https://github.com/PrismLibrary/Prism/blob/be743c2bf7236ea7f0274efdf0567743f1c84d2b/e2e/Forms/src/HelloRegions/ViewModels/RegionDemoBase.cs

My prob is my Region's VM already inherits from a ViewModelBase that implements INavigationAware & IInitialize .

Initialize should be called anyway. IInitialize and INavigationAware should work for region. So when should we use IRegionAware rather than INavigationAware for example if we just wanna you OnNavigatedTo/From.

The IRegionAware interface has a slightly different set of methods as theyre passing INavigationContext which contains what you'd expect, INavigationParameters. No IInitialize which is annyoing.

What I ended up doing in my app was further separating my base view models:

  • ViewModelBase
  • PageViewModel
  • RegionViewModel

ViewModelBase inherits BindableBase and implements IDestructible. I'm passing things like INavigationService as well as my logging implementation. This doesn't have any of the lifecycle code in it.

PageViewModel inherits ViewModelBase which implements IInitialize, IInitializeAsync, INavigationAware, all of my pages use this base class

RegionViewMode inherits ViewModelBase and implements IRegionAware, IRegionMemberLifetime, all of my regions use this base class. I added the following code to give myself an experience similar to IInitialise, its definitely a cringe implementation but 🤷‍♂️

private bool _initialized = false;

public virtual void OnNavigatedTo(INavigationContext navigationContext)
{
    if (!_initialized)
    {
        _initialized = true;

        Initialize(navigationContext.Parameters);
    }
}

protected virtual void Initialize(INavigationParameters navigationParameters) { }

A bit hacky but now I can override Initialize in my region view model and run whatever startup code I need to without constantly having to guard for that behaviour in a region view model.

In response to your question of when to use INavigationAware and when to use IRegionAware:

  • Use INavigationAware when navigating between pages
  • Use IRegionAware when navigating between regions

That's an awesome anwer you gave here, thanks for your time. I was hesitating to go through your suggestions but I don't see any other way for now but to have one BaseViewModel per "concept" (Pages, regions ...), implementing their specific interfaces/navigation events .

For now, I'll keep this bug open, as I'm not sure this is an expected behavior - the Initialize tweak does the job for now.

thanks for the workaround @Axemasta 🙌
i have also implemented your suggestion and so far it's working fine for me. The only thing that bothers me is that _initialized get cleared whenever a navigation to a different region happens.

I have also tried implementing IRegionMemberLifetime and override KeepAlive which doesn't help. In my case Initialize is called all the time in OnNavigatedTo because _initialized is always false

Glad I could help @nor0x 😁

That is strange, I haven't had any issues with Initialize firing extra times, I have KeepAlive set to true and the region I but the workaround for navigates many times and I haven't noticed it.

Here is a sample of the region view model I'm using, when you run it you see the regions running their init code only once. Maybe this will help diagnose the issue?

RegionInitializeSample.zip

Was this page helpful?
0 / 5 - 0 ratings