Prism.Unity.Forms INavigatedAware OnNavigatedTo is not called when navigating multiple pages deep.

Brian_SnoddyBrian_Snoddy USUniversity ✭✭
edited March 2018 in Xamarin.Forms

Prism.Unity 7.0.0.396 and Xamarin Forms 2.5.0.280555

I just started playing around with Prism with Forms. When navigating 3 deep my third page's viewmodel OnNavigatedTo is not called. Pages 1 and 2 are the same so I am not sure why it doesn't work on Page3.
I can however Navigate from Page 1 to Page 3 and OnNavigatedTo will get called on Page 3. When I try to navigate from page 1 to page2 to page3 it does not.

I have attached a simple repro of my issue in the attached zip file. If anyone can help me figure out what I have done wrong I would greatly appreciate it.

My app.xaml.cs
public partial class App : PrismApplication
{
public App(IPlatformInitializer initializer = null) : base(initializer)
{
}
protected override void OnInitialized()
{
InitializeComponent();
NavigationService.NavigateAsync("HomePage");

    }
    protected override void RegisterTypes(IContainerRegistry containerRegistry)
    {
        containerRegistry.RegisterForNavigation<NavigationPage>();
        //Pages
        containerRegistry.RegisterForNavigation<HomePage, HomeViewModel>();
        containerRegistry.RegisterForNavigation<Page1Page, Page1ViewModel>();
        containerRegistry.RegisterForNavigation<Page2Page, Page2ViewModel>();
        containerRegistry.RegisterForNavigation<Page3Page, Page3ViewModel>();
    }

}

public class HomeViewModel : PageViewModelBase, INavigatedAware
{
INavigationService _navigationService;
public ICommand NavigateToActivityManagementPageCommand { get; private set; }
public ICommand NavigateToPage1PageCommand { get; private set; }
public string SideDrawerHeaderIcon { get; }
public string SideDrawerHeaderTitle { get; }
public string SideDrawerSubHeaderTitle { get; }
public HomeViewModel(INavigationService navigationService)
{
_navigationService = navigationService;
NavigateToPage1PageCommand = new Command(() => NavigateToPage1Page());
}
private void NavigateToPage1Page()
{
_navigationService.NavigateAsync("Page1Page");
}
public void OnNavigatedFrom(NavigationParameters parameters)
{
throw new NotImplementedException();
}
public void OnNavigatedTo(NavigationParameters parameters)
{
throw new NotImplementedException();
}
}
public class Page1ViewModel : PageViewModelBase, INavigatedAware, IDestructible
{
INavigationService _navigationService;
private string _inputResult;
public string InputResult
{
get { return _inputResult; }
set { SetProperty(ref _inputResult, value); }

    }

    public Page1ViewModel(INavigationService navigationService)
    {
        _navigationService = navigationService;
        NavigateToPage2PageCommand = new Command(NavigateToPage2Page);
    }
    public Command NavigateToPage2PageCommand { get; private set; }
    private void NavigateToPage2Page()
    {
        var selected = 1;
        var parameter = new NavigationParameters();
        parameter.Add("selected", selected);
        _navigationService.NavigateAsync("Page2Page", parameter);
    }
    public void OnNavigatedFrom(NavigationParameters parameters)
    {

    }
    public void OnNavigatedTo(NavigationParameters parameters)
    {

    }
    public void Destroy()
    {

    }
}

public class Page2ViewModel : PageViewModelBase, INavigatedAware, IDestructible
{
INavigationService _navigationService;
public Page2ViewModel(INavigationService navigationService)
{
_navigationService = navigationService;
NavigateToPage3PageCommand = new Command(NavigateToSelectedPage);
}
public void OnNavigatedFrom(NavigationParameters parameters)
{
throw new NotImplementedException();
}
public void OnNavigatedTo(NavigationParameters parameters)
{
}
public Command NavigateToPage3PageCommand { get; private set; }
private void NavigateToSelectedPage()
{
//InputResult = "Waiting for result...";
var SelectedItem = 2;
var parameter = new NavigationParameters();

        parameter.Add("selectedItem", SelectedItem);
        _navigationService.NavigateAsync("Page3Page", parameter);
    }

    public void Destroy()
    {

    }
}

public class Page3ViewModel : PageViewModelBase, INavigatedAware ,IDestructible
{
INavigationService _navigationService;
private string _testText;
public string testText
{
get { return _testText; }
set { SetProperty(ref _testText, value); }
}

    public Page3ViewModel(INavigationService navigationService)
    {
        _navigationService = navigationService;
        testText = "Did OnNavigateTo get called?";
    }
    public async void Back()
    {
        await _navigationService.GoBackAsync();
    }
    public void OnNavigatedFrom(NavigationParameters parameters)
    {
        throw new NotImplementedException();
    }
    public void OnNavigatedTo(NavigationParameters parameters)
    {
        var selectedItem = (string)parameters["selectedItem"];
        testText = "OnNavigateTo was called!!";
    }
    public void Destroy()
    {
    }


}

Best Answer

Answers

  • Brian_SnoddyBrian_Snoddy USUniversity ✭✭

    @BrianLagunas I really hate to ask but would you mind taking a look please? I am sure it is something I overlooked but I am just not seeing what the issue could be.

    Each page has a button that navigates to the next page. When navigating to page 3 OnNavigatedTo is not called and my breakpoint is not hit on that page.

  • Brian_SnoddyBrian_Snoddy USUniversity ✭✭

    @BrianLagunas Thank You and I am so sorry to have bothered you with such a simple mistake. I completely overlooked the exception on the onnavigatedfrom on page2. Again I apologize my eyes just didn't see that I hadn't removed those.

  • GnanaGnana Member ✭✭

    Hi @BrianLagunas ,

    Do you any idea about, how to add collection in INavigatedAware.OnNavigatedTo(). I'm trying to add my collection this method like below,

        public class AccordionViewModel : BindableBase, INotifyPropertyChanged, INavigationAware
        {
            #region Fields
    
            int counter = 11;
    
            #endregion
    
            #region Properties
    
            public ObservableCollection<Contact> ContactsInfo { get; set; }
    
            protected INavigationService _NavigationService { get; set; }
    
            #endregion
    
            #region Constructor
    
            public AccordionViewModel(INavigationService NavigationService):base()
            {
                _NavigationService = NavigationService;
    
            }
    
            private void AddItems()
            {
                ContactsInfo = new ObservableCollection<Contact>();
                Assembly assembly = typeof(Accordion.MainPage).GetTypeInfo().Assembly;
                int i = 0;
                foreach (var cusName in CustomerNames)
                {
                    if (counter == 13)
                        counter = 1;
                    var contact = new Contact(cusName);
                    contact.CallTime = CallTime[i];
                    contact.PhoneImage = ImageSource.FromResource("ListViewPrism.Images.PhoneImage.png", assembly);
                    contact.ContactImage = ImageSource.FromResource("ListViewPrism.Images.Image" + counter + ".png", assembly);
                    contact.AddContact = ImageSource.FromResource("ListViewPrism.Images.AddContact.png", assembly);
                    contact.NewContact = ImageSource.FromResource("ListViewPrism.Images.NewContact.png", assembly);
                    contact.SendMessage = ImageSource.FromResource("ListViewPrism.Images.SendMessage.png", assembly);
                    contact.BlockSpan = ImageSource.FromResource("ListViewPrism.Images.BlockSpan.png", assembly);
                    contact.CallDetails = ImageSource.FromResource("ListViewPrism.Images.CallDetails.png", assembly);
                    i++;
                    ContactsInfo.Add(contact);
                    counter++;
                }
            }
    
    
            #endregion
    
            #region Fields
    
            string[] CustomerNames = new string[] {
                "Kyle",
                "Gina",
                "Irene",
                "Katie",
                "Oscar",
                "Ralph",
                "Torrey",
                "William",
                "Bill",
                "Daniel",
                "Frank",
                "Brenda",
                "Danielle",
                "Fiona",
                "Howard",
                "Jack",
                "Larry",
                "Holly",
                "Liz",
                "Pete",
                "Steve",
                "Vince",
                "Katherin",
                "Aliza",
                "Masona" ,
                "Lia" ,
                "Jacob  " ,
                "Jayden " ,
                "Ethani  " ,
                "Noah   " ,
                "Lucas  " ,
                "Logan  " ,
                "John  " ,
            };
    
            string[] CallTime = new string[]
            {
                "India, 1 days ago",
                "India, 1 days ago",
                "India, 1 days ago",
                "India, 1 days ago",
                "India, 1 days ago",
                "India, 2 days ago",
                "India, 2 days ago",
                "India, 2 days ago",
                "India, 2 days ago",
                "India, 2 days ago",
                "India, 3 days ago",
                "India, 3 days ago",
                "India, 3 days ago",
                "India, 3 days ago",
                "India, 3 days ago",
                "India, 4 days ago",
                "India, 4 days ago",
                "India, 4 days ago",
                "India, 4 days ago",
                "India, 4 days ago",
                "India, 5 days ago",
                "India, 5 days ago",
                "India, 5 days ago",
                "India, 5 days ago",
                "India, 5 days ago",
                "India, 6 days ago",
                "India, 6 days ago",
                "India, 6 days ago",
                "India, 6 days ago",
                "India, 6 days ago",
                "India, 1 week ago",
                "India, 1 week ago",
                "India, 1 week ago"
            };
    
            #endregion
    
            #region Interface Member
    
            public event PropertyChangedEventHandler PropertyChanged;
    
            public void OnPropertyChanged(string name)
            {
                if (this.PropertyChanged != null)
                    this.PropertyChanged(this, new PropertyChangedEventArgs(name));
            }
    
            void INavigatedAware.OnNavigatedFrom(INavigationParameters parameters)
            {
            }
    
           async void INavigatedAware.OnNavigatedTo(INavigationParameters parameters)
            {
                await Task.Delay(1000);
               ** AddItems();** // adding collection here doesn't reflect in my UI though all 33 items gets added in underlying colection. But when add in constructor, i see the items in UI
    
            }
    
            void INavigatingAware.OnNavigatingTo(INavigationParameters parameters)
            {
            }
    
            #endregion
        }
    

    Am new to prism . Any help will be appreciable.
    Thanks in advance.

  • NMackayNMackay GBInsider, University mod

    @Gnana said:
    Hi @BrianLagunas ,

    Do you any idea about, how to add collection in INavigatedAware.OnNavigatedTo(). I'm trying to add my collection this method like below,

        public class AccordionViewModel : BindableBase, INotifyPropertyChanged, INavigationAware
        {
            #region Fields
    
            int counter = 11;
    
            #endregion
    
            #region Properties
    
            public ObservableCollection<Contact> ContactsInfo { get; set; }
    
            protected INavigationService _NavigationService { get; set; }
    
            #endregion
    
            #region Constructor
    
            public AccordionViewModel(INavigationService NavigationService):base()
            {
                _NavigationService = NavigationService;
    
            }
    
            private void AddItems()
            {
                ContactsInfo = new ObservableCollection<Contact>();
                Assembly assembly = typeof(Accordion.MainPage).GetTypeInfo().Assembly;
                int i = 0;
                foreach (var cusName in CustomerNames)
                {
                    if (counter == 13)
                        counter = 1;
                    var contact = new Contact(cusName);
                    contact.CallTime = CallTime[i];
                    contact.PhoneImage = ImageSource.FromResource("ListViewPrism.Images.PhoneImage.png", assembly);
                    contact.ContactImage = ImageSource.FromResource("ListViewPrism.Images.Image" + counter + ".png", assembly);
                    contact.AddContact = ImageSource.FromResource("ListViewPrism.Images.AddContact.png", assembly);
                    contact.NewContact = ImageSource.FromResource("ListViewPrism.Images.NewContact.png", assembly);
                    contact.SendMessage = ImageSource.FromResource("ListViewPrism.Images.SendMessage.png", assembly);
                    contact.BlockSpan = ImageSource.FromResource("ListViewPrism.Images.BlockSpan.png", assembly);
                    contact.CallDetails = ImageSource.FromResource("ListViewPrism.Images.CallDetails.png", assembly);
                    i++;
                    ContactsInfo.Add(contact);
                    counter++;
                }
            }
            
    
            #endregion
    
            #region Fields
    
            string[] CustomerNames = new string[] {
                "Kyle",
                "Gina",
                "Irene",
                "Katie",
                "Oscar",
                "Ralph",
                "Torrey",
                "William",
                "Bill",
                "Daniel",
                "Frank",
                "Brenda",
                "Danielle",
                "Fiona",
                "Howard",
                "Jack",
                "Larry",
                "Holly",
                "Liz",
                "Pete",
                "Steve",
                "Vince",
                "Katherin",
                "Aliza",
                "Masona" ,
                "Lia" ,
                "Jacob  " ,
                "Jayden " ,
                "Ethani  " ,
                "Noah   " ,
                "Lucas  " ,
                "Logan  " ,
                "John  " ,
            };
    
            string[] CallTime = new string[]
            {
                "India, 1 days ago",
                "India, 1 days ago",
                "India, 1 days ago",
                "India, 1 days ago",
                "India, 1 days ago",
                "India, 2 days ago",
                "India, 2 days ago",
                "India, 2 days ago",
                "India, 2 days ago",
                "India, 2 days ago",
                "India, 3 days ago",
                "India, 3 days ago",
                "India, 3 days ago",
                "India, 3 days ago",
                "India, 3 days ago",
                "India, 4 days ago",
                "India, 4 days ago",
                "India, 4 days ago",
                "India, 4 days ago",
                "India, 4 days ago",
                "India, 5 days ago",
                "India, 5 days ago",
                "India, 5 days ago",
                "India, 5 days ago",
                "India, 5 days ago",
                "India, 6 days ago",
                "India, 6 days ago",
                "India, 6 days ago",
                "India, 6 days ago",
                "India, 6 days ago",
                "India, 1 week ago",
                "India, 1 week ago",
                "India, 1 week ago"
            };
    
            #endregion
    
            #region Interface Member
    
            public event PropertyChangedEventHandler PropertyChanged;
    
            public void OnPropertyChanged(string name)
            {
                if (this.PropertyChanged != null)
                    this.PropertyChanged(this, new PropertyChangedEventArgs(name));
            }
    
            void INavigatedAware.OnNavigatedFrom(INavigationParameters parameters)
            {
            }
    
           async void INavigatedAware.OnNavigatedTo(INavigationParameters parameters)
            {
                await Task.Delay(1000);
               ** AddItems();** // adding collection here doesn't reflect in my UI though all 33 items gets added in underlying colection. But when add in constructor, i see the items in UI
    
            }
    
            void INavigatingAware.OnNavigatingTo(INavigationParameters parameters)
            {
            }
    
            #endregion
        }
    

    Am new to prism . Any help will be appreciable.
    Thanks in advance.

    You don't need to implement OnPropertyChanged, it's taken care of in Prism's BaseViewModel. Just make your ViewModel on Base class inherit from BindableBase.

    Here's a sample of how to setup collections etc
    https://github.com/mackayn/CrudSample/blob/master/CrudSample/ViewModels/MainPageViewModel.cs

    Just refer to the official samples & documentation

    https://prismlibrary.github.io/docs/xamarin-forms/creating-your-first-prism-app.html
    https://github.com/xamarin/xamarin-forms-samples

  • GnanaGnana Member ✭✭

    Hi @NMackay ,

    Thanks for your solution.

    My doubt is
    In prism 7.1

    App.xaml.cs :
            protected override void RegisterTypes(IContainerRegistry containerRegistry)
            {
                containerRegistry.RegisterForNavigation<NavigationPage>();
                containerRegistry.RegisterForNavigation<MainPage, AccordionViewModel>();
    
            }
    Viewmodel.cs :
    async void INavigatedAware.OnNavigatedTo(INavigationParameters parameters)
            {
    
                AddItems();
    
            }
    private void AddItems()
            {
                ContactsInfo = new ObservableCollection<Contact>();
                foreach (var cusName in CustomerNames)
                {
                    var contact = new Contact(cusName);
                    contact.NewContact = ImageSource.FromResource("ListViewPrism.Images.NewContact.png", assembly);
                    contact.CallDetails = ImageSource.FromResource("ListViewPrism.Images.CallDetails.png", assembly);
                    ContactsInfo.Add(contact);
                }
            }
    

    is not working. and the same case is working fine in prism 6.3.0 that is below.

    App.xaml.cs:
    protected override void RegisterTypes()
            {
                Container.RegisterTypeForNavigation<NavigationPage>();
                Container.RegisterTypeForNavigation<MainPage>();
            }
    ViewModel.cs:
    public void OnNavigatedTo(NavigationParameters parameters)
    {
                var modelDatas = new List<Model>();
                modelDatas .Add(new Model() { Name= "John" });
                modelDatas .Add(new Model() { Name = "Mark" });
                modelDatas .Add(new Model() { Name = "Jenny" });
    
                ItemsSourcecollection = new ObservableCollection<Model>(modelDatas);
     }
    

    Can you suggest me a solution to short our this. Am i missing anything..

  • NMackayNMackay GBInsider, University mod

    @Gnana said:
    Hi @NMackay ,

    Thanks for your solution.

    My doubt is
    In prism 7.1

    App.xaml.cs :
            protected override void RegisterTypes(IContainerRegistry containerRegistry)
            {
                containerRegistry.RegisterForNavigation<NavigationPage>();
                containerRegistry.RegisterForNavigation<MainPage, AccordionViewModel>();
                
            }
    Viewmodel.cs :
    async void INavigatedAware.OnNavigatedTo(INavigationParameters parameters)
            {
    
                AddItems();
    
            }
    private void AddItems()
            {
                ContactsInfo = new ObservableCollection<Contact>();
                foreach (var cusName in CustomerNames)
                {
                    var contact = new Contact(cusName);
                    contact.NewContact = ImageSource.FromResource("ListViewPrism.Images.NewContact.png", assembly);
                    contact.CallDetails = ImageSource.FromResource("ListViewPrism.Images.CallDetails.png", assembly);
                    ContactsInfo.Add(contact);
                }
            }
    

    is not working. and the same case is working fine in prism 6.3.0 that is below.

    App.xaml.cs:
    protected override void RegisterTypes()
          {
              Container.RegisterTypeForNavigation<NavigationPage>();
              Container.RegisterTypeForNavigation<MainPage>();
          }
    ViewModel.cs:
    public void OnNavigatedTo(NavigationParameters parameters)
    {
                var modelDatas = new List<Model>();
                modelDatas .Add(new Model() { Name= "John" });
                modelDatas .Add(new Model() { Name = "Mark" });
                modelDatas .Add(new Model() { Name = "Jenny" });
    
                ItemsSourcecollection = new ObservableCollection<Model>(modelDatas);
     }
    

    Can you suggest me a solution to short our this. Am i missing anything..

    AddItems is not awaitable, why await it?

  • GnanaGnana Member ✭✭

    Sorry. I actually forgot to remove async in code....

    I have attached my simple sample. Can you please check out and help me sort out this.

    i really have no idea about my mistake..

  • NMackayNMackay GBInsider, University mod

    @Gnana said:
    Sorry. I actually forgot to remove async in code....

    I have attached my simple sample. Can you please check out and help me sort out this.

    i really have no idea about my mistake..

    I'll have a look tonight after work.

  • GnanaGnana Member ✭✭

    Thanks for your help..

    I could sort out and solve the issue. If i initialize the observablecollection in the constructor , it works. Items displayed as expected in UI.

    ViewModel()
    {
             ContactsInfo = new ObservableCollection<Contact>();
    }
    private void AddItems()
            {
                   foreach (var cusName in CustomerNames)
                {
                    var contact = new Contact(cusName);
                    contact.NewContact = ImageSource.FromResource("ListViewPrism.Images.NewContact.png", assembly);
                    contact.CallDetails = ImageSource.FromResource("ListViewPrism.Images.CallDetails.png", assembly);
                    ContactsInfo.Add(contact);
                }
            }
    

    But can you please explain me. Why it doesn't work properly and items didn't display when i initilaize in OnNaviagtedTo() method...

  • NMackayNMackay GBInsider, University mod
    edited February 13

    @Gnana said:
    Thanks for your help..

    I could sort out and solve the issue. If i initialize the observablecollection in the constructor , it works. Items displayed as expected in UI.

    ViewModel()
    {
             ContactsInfo = new ObservableCollection<Contact>();
    }
    private void AddItems()
            {
                   foreach (var cusName in CustomerNames)
                {
                    var contact = new Contact(cusName);
                    contact.NewContact = ImageSource.FromResource("ListViewPrism.Images.NewContact.png", assembly);
                    contact.CallDetails = ImageSource.FromResource("ListViewPrism.Images.CallDetails.png", assembly);
                    ContactsInfo.Add(contact);
                }
            }
    

    But can you please explain me. Why it doesn't work properly and items didn't display when i initilaize in OnNaviagtedTo() method...

    I was going to suggest that very thing.

    Depending on the rendering sequence, if OC's haven't been initialised with a new empty instance in the ViewModel constructor, the Listview simply ignores the changes, the binding engine seems to ignore the binding. Happens with 3rd party lists too so best practice is to initialise a new empty collection/list in the class constructor. Found 3-4 issues in Telerik Radlist to do with not coping with early binding correctly.

  • GnanaGnana Member ✭✭

    Thanks for your guidance :smile:

Sign In or Register to comment.