INavigationAware: Goback does not go to the right view

Topics: Prism v4 - WPF 4
Aug 19, 2011 at 12:56 PM

Hi

I have to three views : 

V1 : DebiteurMainView

V2 : FactureView

V3: FactureDetailView

Each of these views has its ViewModel that implements INavigationAware and IRegionMemberLifetime.

The navigation scenario is as follow:

V1 -> V2->V3

From V3 when i goback, i directly go the V1 instead V2.

Here is my code

V1: DebiteurMainViewModel

 #region INavigationAware Members

        public bool IsNavigationTarget(NavigationContext navigationContext)
        {
            return true;
        }

        public void OnNavigatedFrom(NavigationContext navigationContext)
        {
            
        }

        public void OnNavigatedTo(NavigationContext navigationContext)
        {
         
        }

       

        #region IRegionMemberLifetime Members

        public bool KeepAlive
        {
            get { return false; }
        }

        

V2 : FactureViewModel
     private DelegateCommand<object> _goBackToMainViewCommand;

        public DelegateCommand<object> GoBackToMainViewCommand
        {
            get {
                if (_goBackToMainViewCommand == null)
                    _goBackToMainViewCommand = new DelegateCommand<object>(GoBack, CanGoBack);
                return _goBackToMainViewCommand;
            }
            set { _goBackToMainViewCommand = value; }
        }

        public void GoBack(object obj)
        {
            _navigationService.Journal.GoBack();
        }

        public bool CanGoBack(object obj)
        {
             return _navigationService.Journal.CanGoBack;
        }



        public bool IsNavigationTarget(NavigationContext navigationContext)
        {
        
           
            return true;
        }

        public void OnNavigatedFrom(NavigationContext navigationContext)
        {
           
        }

        public void OnNavigatedTo(NavigationContext navigationContext)
        {
           
            _navigationService = navigationContext.NavigationService;
            int idDpdebt00 = Int32.Parse(navigationContext.Parameters["ID_DPDEBT00"]);
            string idClient = navigationContext.Parameters["ID_DPCLIT00"];
            Client = _dpclit00Repository.GetGlientByID(Int32.Parse(idClient));
            Dpdebt00 = _dpdebt00Repository.GetDPDEBT00ByID(idDpdebt00);
            Factures = _dpdebt10Repository.GetFactures(idDpdebt00);
            
        }

  

        public bool KeepAlive
        {
            get { return false; }
        }

       

V3: FactureDetailViewModel

  private DelegateCommand<object> _goBackCommand;

      public DelegateCommand<object> GoBackCommand
      {
          get
          {
              if (_goBackCommand == null)
                  _goBackCommand = new DelegateCommand<object>(GoBack, CanGoBack);
              return _goBackCommand;
          }
          set { _goBackCommand = value; }
      }

      public void GoBack(object obj)
      {

            _navigationService.Journal.GoBack();

       
      }

      public bool CanGoBack(object obj)
      {
           return _navigationService.Journal.CanGoBack;
      }

 #region INavigationAware Members

      public bool IsNavigationTarget(NavigationContext navigationContext)
      {
         
           return true;
      }

      public void OnNavigatedFrom(NavigationContext navigationContext)
      {
         
      }

      public void OnNavigatedTo(NavigationContext navigationContext)
      {
            _navigationService = navigationContext.NavigationService;
            int idClient = Int32.Parse(navigationContext.Parameters["ID_DPCLIT00"]);
            int idFacture = Int32.Parse(navigationContext.Parameters["ID_DPDEBT10"]);
            ID_DPDEBT00 = Int32.Parse(navigationContext.Parameters["ID_DPDEBT00"]);
            Client = _dpclit00Repository.GetGlientByID(idClient);
            Factures = _dpdebt30repository.GatFactureDetails(idFacture);
            Dpdebt10 = _dpdebt10Repository.GetFactureByID(idFacture);
          
      }

      #endregion

      #region IRegionMemberLifetime Members

      public bool KeepAlive
      {
          get { return false; }
      }

      #endregion



 

 

 

Developer
Aug 19, 2011 at 7:24 PM
Edited Aug 23, 2011 at 9:34 PM

Hi,

In my opinion, the problem seems to be caused by the way the views are navigated to rather the views themselves. As explained on the following note from the Navigation Chapter of the Prism MSDN documentation:

"The navigation journal can only be used for region-based navigation operations that are coordinated by the region navigation service. If you use view discovery or view injection to implement navigation within a region, the navigation journal will not be updated during navigation and cannot be used to navigate forward or backward within that region."

This means that if a view is injected or registered into a region instead of navigated to (e.g using the RequestNavigate method) the view will not be registered in the journal.

If this is not the case, it would be helpful if you could provide us with a repro sample application portraying this problem, so we can analyze why it is happening.

I hope you find this useful,

 

Damian Cherubini
http://blogs.southworks.net/dcherubini

Aug 19, 2011 at 8:12 PM

Hi DCherubini

I don't use view injection nor view discovery. I use RequestNavigate method.

Please explain me how can i provide you a sample application? How can i upload?

Thanks

Developer
Aug 23, 2011 at 12:48 PM

Hi,

You could upload your sample to SkyDrive or a similar site.

Thanks,

Guido Leandro Maliandi 
http://blogs.southworks.net/gmaliandi

Aug 25, 2011 at 9:07 AM

Hi GuidoMaliandi

I rechecked my application and realize that the problem does not come from the Goback method.

To go back to a view in my application, the user press ESC key. The problem is that all views are not removed from the memory and all of them catch 

the Key Press Event so they call the Goback method (_navigationService.Journal.GoBack()). That is why my application return to view V1 instead to V2.

So the view is removed from the region but is still in memrory and continues to catch some events like Key events.

How can i cleary remove the view from the region and from memory

Thanks


Developer
Aug 25, 2011 at 2:20 PM

Hi,

Based on my understanding of your scenario, the problem you're experiencing could be caused by the fact that you might be exporting your view as a singleton instance. In order to make sure that your view is not exported in the container as a singleton instance you might check this:

In case you are using Unity, its default behavior is to create a new instance of the view each time it is resolved (unless you have used the RegisterInstance method or the RegisterType method passing a ContainerControlledLifetimeManager as a parameter).

If you are using MEF you will have to decorate your view with the PartCreationPolicy attribute specifying the NonShared value.

You can read more about this in the following chapter from the Prism MSDN documentation:

I hope you find this information handy.

Agustin Adami
http://blogs.southworks.net/aadami

Aug 26, 2011 at 7:59 AM

Hi aadami

I decorate all my views and viewModels with PartCreationPolicy attribute specifying the NonShared value.

I still get this strange behavior.

Thank

Aug 26, 2011 at 10:02 AM

Hi aadami

You can get my app at this url:

https://skydrive.live.com/P.mvc#!/?cid=19206cd461fa3265&sc=documents&id=19206CD461FA3265%21196!cid=19206CD461FA3265&id=19206CD461FA3265%21196&sc=documents

Feel free to contact me for any further questions.

The navigation scenario is:

DebiteurMainView -> FactureView -> FactureDetailView

and the return should be :

FactureDetailView -> FactureView -> DebiteurMainView.

Unfortunatly i get   FactureDetailView  ->  DebiteurmainView 

Sorry for the size of the projet. I could not make a light repro.

Thanks

Developer
Aug 26, 2011 at 6:58 PM

Hi,

The application that you provided doesn’t works for us (the shell appears but the views aren’t shown). It may be because it needs some resources, like a database, which we don’t have.

It would be helpful if you could provide us with a repro sample application that only uses the views in which you are experimenting the problem and that mocks any required data.

Meanwhile, I have checked the code that you use to navigate back in the FactureView and the FactureDetailView and I have seen that you invoke the command used to navigate back pressing the ESC key in both views. It may be possible that the key press is being “received” by both views so that when the FactureView is navigated back to, it’s navigate back command is called immediately and it could look like the view was skipped in the navigation process.

 

I hope you find this useful,

Damian Cherubini
http://blogs.southworks.net/dcherubini

Aug 27, 2011 at 4:24 AM

hi DCherubini

Please run the application in Debug mode not in release. The database is in the same directoty (Application\Veto2000Application\Veto2000\bin\Debug\) as the .exe.  

You are right. When i display FactureDetailView and press ESC key, i realize that the Goback method of the FactureView run first. So as you said the key press is received 

by both views. FactureView receive first and FactureDetailView at the end.

Why FactureView is not destroyed when i move to FactureDetailView?

What can skip the view in the navigation?

Here is the repo without data (Veto2000ApplicationWithoutData)

https://skydrive.live.com/#!/?cid=19206cd461fa3265&sc=documents&id=19206CD461FA3265%21196!cid=19206CD461FA3265&id=19206CD461FA3265%21196&sc=documents

 

Thanks

Developer
Aug 29, 2011 at 8:50 PM

Hi,

We were able to run and analyze your sample application fine, thank you.

Regarding your problem, I believe that the reason of why the views are being kept alive might be because the interaction trigger is holding strong references the them. There is an active work item in the Prism’s Issue Tracker regarding this problem.

As a workaround for this you can export the views and view models decorating them with the PartCreationPolicy attribute specifying the NonShared value and replace the CanGoBack method in the view models with the following one:

public bool CanGoBack(object obj)
{
        var activeView = _regionManager.Regions[WellknownRegionNames.MainContentRegion].ActiveViews.FirstOrDefault() as UserControl;
        if (activeView.DataContext == this)
        {
                return _navigationService.Journal.CanGoBack;
        }
        else
        {
                return false;
        }
}

However, have in mind that this won’t solve the problem with the interaction trigger keeping the views / view models alive and it will produce memory leaks.

I hope you find this useful,

Damian Cherubini
http://blogs.southworks.net/dcherubini

Aug 31, 2011 at 8:47 AM

Hi

Thank you for answer. 

We have found another workaround to avoid memory leaks.

Blochaou François