RequestNavigate - "View already exists in region"

Nov 2, 2010 at 10:41 PM

If I use a ContentControl as my navigation region, the first time I navigate that region to a view it works fine. When I navigate to a different view, that works fine. However, when I navigate back to the original view, I get an error - "View already exists in region".

I expected my existing view to get activated instead of getting this error.

What is the logic behind raising this error instead of simply activing the existing view?

Nov 2, 2010 at 10:43 PM

This even happens if I return true from INavigationAware.IsNavigationTarget. For instance:

return navigationContext.Uri.OriginalString == "/path/to/this/view";

Nov 2, 2010 at 11:34 PM
Edited Nov 2, 2010 at 11:35 PM

I don't even care what the logic is behind raising the error. If anyone can suggest a work-around I'm all for it! Thanks.

(I'm in a hurry to finish this project before my boss hears about any of that Silverlight is Dead news that's been going around.)

Nov 2, 2010 at 11:59 PM
Edited Nov 3, 2010 at 12:40 AM

OK, nevermind. Sorry, my fault!

Returning true from INavigationAware.IsNavigationTarget does work, you just have to make sure that you're actually returning true and not what you think is true!

(Not implementing INavigationAware at all works as well if you don't need to implement it.)

Thanks.

Nov 3, 2010 at 12:00 AM

Admins: Feel free to delete this discussion, thank you.

Nov 3, 2010 at 2:39 PM
Edited Nov 3, 2010 at 2:43 PM

Hi Wayne,

Nice to see that you figured out how to get your scenario working. As there are several opinions around the role of Silverlight, I think that you can find the following official blog posts interesting:

Hope this helps.

Fernando Antivero
http://blogs.southworks.net/fantivero

 

Nov 3, 2010 at 4:44 PM

Thanks fantivero!

Apr 14, 2011 at 8:27 AM

Good day,

I seem to have the same problem. Not sure why it only happens in this scenario.

If I remove the INavigationAware it seems to work but I'm dependent on the Prism navigation to execute certain initialisations.

The only complexity in this scenario is I load a user control in the main region with RequestNavigate and the loaded user control also contains a region which I load other module also using RequestNavigate. So it’s a region in a region.

In other places I do the same and it works fine.

Thanks

Apr 14, 2011 at 8:27 AM

Good day,

I seem to have the same problem. Not sure why it only happens in this scenario.

If I remove the INavigationAware it seems to work but I'm dependent on the Prism navigation to execute certain initialisations.

The only complexity in this scenario is I load a user control in the main region with RequestNavigate and the loaded user control also contains a region which I load other module also using RequestNavigate. So it’s a region in a region.

In other places I do the same and it works fine.

Thanks

Apr 18, 2011 at 9:07 AM

I wonder if someone can advise me on the RequestNavigate. I did post the question and log an incident on the patterns and practises website for Prism but nobody responded.

We use RequestNavigate extensively to populate the different regions on the composite UI. In this scenario, I’ve got a user control with a region and using RequestNavigate I populate the region with a user control that consist out of its own regions where I load other user controls.

 

This works perfectly on most areas but for some reason if I implement the INavigationAware in the viewmodels and set the inner RequestNavigation to load all the other user controls in the OnNavigatedTo as stated above it load the first time perfectly without any issues but if I navigate away and then back it fails to load the inner user controls. If I move the RequestNavigate from the OnNavigatedTo to the load of the user control it works.

So I did solve the problem but don't like the solution and would like to keep everything in the viewmodel. Any advice will be appreciated?

 

 

Developer
Apr 20, 2011 at 7:30 PM

Hi,

It could be helpful if you could provide us with a repro sample of your solution, so that we can help you find out the cause of the unexpected behavior you're experiencing.

Thanks,

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

Apr 23, 2011 at 8:03 AM

Hi eraubenheimer,

If you uses MEF, you must use the same string (case sensitive) in export attribute with your view name.

This works:

    [Export("View1")]
    public partial class View1 : UserControl, INavigationAware

This won't work:

    [Export("view1")]
    public partial class View1 : UserControl, INavigationAware

The difference only in "V" & "v". So once you navigate to it and when you try to re-navigate back it will complain ""View already exists in region".

I tried this on Prism 4 & silverlight 4.

Apr 26, 2011 at 4:50 AM

I dont think its a case sensitive issue. You can give any contract name to your exports. I think it is because the view is not marked as CreationPolicy.NonShared. So when you navigate back to it the region tries to add the same instance of the view to its ViewsCollection and it gives the above error message. Also setting the RegionMemberLifetime(KeepAlive = false) will make sure view is deactivated when you navigate away from the view.

Apr 26, 2011 at 6:30 AM

That's also what I think, I never realized the problem is in contract name case sensitive issue.

That's why I had spent days just to figure this out.

Please download this solution to reproduce the issue.

All the views (View1, View2, View3) implements INavigationAware, and all it's IsNavigationTarget are return true.

So in this case it doesn't matter whether you use [CreationPolicy.NonShared] attribute or not, since the view's instance must be reuse each time it navigated to.

You can navigate to View2 and View3 many times, BUT since the View1 contract name is different from it's class name; you only can navigate to it once.

May 27, 2011 at 8:45 PM
Edited May 27, 2011 at 8:48 PM

Hi, it seems to me that this is a bug in prism (or in documentation)

Documentation says:

"The name used to register the view in the container and to navigate does not have to be associated with the type name; any string will suffice. For example, you can use the full type name instead of a quoted string:

typeof(InboxView).FullName"

So, in my Unity bootstrapper solution i used

container.RegisterType<object,InboxView>("SomeOtherName");

and got exception "View already exists in region"

After some prism code investigation i found that there is a method which test view in region for acceptance and it checks view for type name/full type name, not the registered in unity name of view

RegionNavigationContentLoader.cs:

   protected virtual IEnumerable<object> GetCandidatesFromRegion(IRegion region, string candidateNavigationContract)
        {
            if (region == null) throw new ArgumentNullException("region");
            return region.Views.Where(v =>
                string.Equals(v.GetType().Name, candidateNavigationContract, StringComparison.Ordinal) ||
                string.Equals(v.GetType().FullName, candidateNavigationContract, StringComparison.Ordinal));
        }
May 29, 2011 at 3:59 AM

ixolit, good catch. And I think you should report this to the team.

 

Jun 9, 2011 at 3:05 PM
Edited Jun 9, 2011 at 3:05 PM
ixolit wrote:

Hi, it seems to me that this is a bug in prism (or in documentation)

Documentation says:

"The name used to register the view in the container and to navigate does not have to be associated with the type name; any string will suffice. For example, you can use the full type name instead of a quoted string:

typeof(InboxView).FullName"

So, in my Unity bootstrapper solution i used

container.RegisterType<object,InboxView>("SomeOtherName");

and got exception "View already exists in region"

After some prism code investigation i found that there is a method which test view in region for acceptance and it checks view for type name/full type name, not the registered in unity name of view

RegionNavigationContentLoader.cs:

   protected virtual IEnumerable<object> GetCandidatesFromRegion(IRegion region, string candidateNavigationContract)
        {
            if (region == null) throw new ArgumentNullException("region");
            return region.Views.Where(v =>
                string.Equals(v.GetType().Name, candidateNavigationContract, StringComparison.Ordinal) ||
                string.Equals(v.GetType().FullName, candidateNavigationContract, StringComparison.Ordinal));
        }

 

I can confirm this bug aswell! Anyone reported this yet?

Jul 1, 2011 at 5:18 PM

Glad to find this thread... I too had noticed that (using MEF) the name used to register my views HAD to match the actual class name of the view which seemed lame...   Thanks for filing the bug!

Developer
Oct 18, 2011 at 9:45 PM

Hi,

You might find the following blog post useful, which contains more information about this:

I hope you find this useful.

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


Jul 8, 2013 at 2:25 PM
Hello,

Will it be fixed some day ? It looks like a serious bug to me.
We are using custom Export attribut names in our Views, thus we are always getting the exception, unless we always return true in IsNavigationTarget.

Regards,

Adrien
Developer
Jul 8, 2013 at 4:10 PM
Hi Adrien,

I believe you might find the following work items useful, where modified implementations of the RegionNavigationContentLoaders (the classes that are in charge of finding the "candidate" views in a region for navigation) are attached:

The aforementioned implementations were modified to also take into account the contract names used to export the views, avoiding this issue.
Based on my understanding, in order to use the MEF implementations in your application you will need to export it with the following attributes:
[Export(typeof(IRegionNavigationContentLoader))]
[PartCreationPolicy(CreationPolicy.Shared)]
I hope this helps,

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