Go grab some snacks and drinks, because this is going to be a long one. It’s been 10 months since the last stable release of Prism 6.3, and there have been a ton of changes since. We have been getting tons of great feedback, fixing a number of issues, implementing new features, and accepting some great PRs. Needless to say, Prism for Xamarin.Forms 7.0 is a massive improvement over it’s previous versions.
Having said that, in order to move Prism for Xamarin.Forms forward and address all the feedback we have been getting, we have had to make a number of breaking changes. I know any time a breaking change is released, it’s extremely frustrating to go update your apps. However, all of these breaks are for the good of the Prism Library and ultimately your applications.
So let’s go ahead and dive right in and discuss all the major changes that you will find in Prism for Xamarin.Forms 7.0.
Net Standard Support
That’s right! It’s finally here. .NET Standard support is here and ready to rock and roll. Now everyone that has been running on the previews just for this can upgrade to the latest Prism for Xamarin.Forms 7.0 stable and get all the benefits that .NET Standard brings.
A New Prism.IoC Namespace
In a large effort to help consolidate a ton of logic and to help clean up repetitive code in the Prism Library as well as your application code, we have introduced a new IoC abstraction that will be used across all platforms that Prism supports; WPF, UWP, and Xamarin.Forms.
In Previous versions of Prism, when you added your favorite DI container, you worked directly against that container API. This makes maintaining the Prism code base more challenging and makes it more difficult for you to change containers in the future. With the release of Prism for Xamarin.Forms 7.0, we have now completely abstracted away the DI container APIs from your code base. Interacting with the container is now done via the IContainerProvider and the IContainerRegistry interfaces. The IContainerProvider interface is used to resolve services from the container. The IContainerRegistry is used to register types with the container. Don’t worry, we understand that sometimes a high level abstraction is limited and you need to use the full blow features of the underlying container. To achieve this, access to the actual DI container can be achieved by using the GetContainer() extension method off of the IContainerRegistry and IContainerProvider interfaces.
PrismApplication API Changes – (Breaking)
Now the really big one. We have made a number of API changes to the PrismApplication class in order to make the API more intuitive and guide developers on it’s implementation. This means that you will have to make changes to your App.cs file in order to compile.
Here are the changes that were made that you will definitely have to update:
- Container property is now of type IContainerProvider – you no longer have direct access to the DI container. So if you are using any Resolve methods off of it, you will need to update your code to use the new IContainerProvide API to resolve objects.
- Changed signature of RegisterTypes() to RegisterTypes(IContainerRegistry containterRegistry) – the API now passes the IContainerRegistry in the RegisterTypes method for you to use to register your types with Prism. This makes the API much cleaner, clearer, and concise across all platforms.
- Changed signature of ConfigureModuleCatalog() to ConfigureModuleCatalog(IModuleCatalog moduleCatalog) – the API now passes the module catalog into the ConfigureModuleCatalog method. You no longer have to rely on the ModuleCatalog property to add modules to your app.
- Removed ModuleCatalog property – it didn’t make since to keep the ModuleCatalog proeprty since we are now providing it to you in the ConfigurModuleCatalog method. It makes no sense to modify it outside that method.
- Renamed RegisterTypeForNavigation to RegisterForNavigation – This was done to align the API with the new IContainerRegistry API.
- Changed order of application initialization process (platform specific types are registered before application types) – we have identified a number of scenarios that forced us to change the order in which the initialization of a Prism application occurs. Things should work much better now.
Here are some other notable changes that most likely won’t impact your applications unless you are doing something really advanced.
- Removed CreateContainer() method
- Removed CreateNavigationService() method
- Removed CreateLogger() method
- Removed CreateModuleManager() method
- Removed CreateModuleCatalog() method
- Renamed ConfigureContainer to RegisterRequiredTypes(IContainerRegistry containterRegistry)
IModule API Changes – (Breaking)
If you’re using modularity then you’ll immediately get a build error as your modules have to implement a couple of more methods.
Here are the changes made to IModule:
- Obsolete Initialize() method – move all existing code into RegisterTypes and OnInitialized methods
- Added RegisterTypes(IContainerRegistry containerRegistry) method – used to register types with the container.This method is the first method to be called after the module’s ctor.
- Added OnInitialized() method – used to perform any action after the module has been created, and types have been registered with the container.
IPlatformInitializer API Changes – (Breaking)
Related to the above breaking changes, the IPlatformInitializer has had it’s API updated to accommodate the new IContainerRegistry API.
- Changed RegisterTypes signature to RegisterTypes(IContainerRegistry containerRegistry)
TabbedPage Navigation Behavior Change – (Breaking)
We have had a ton of great feedback regarding navigating with TabbedPages. Let’s just say, TabbedPages are a very complex UI paradigm to deal with within a Xamarin.Forms app. So let’s briefly cover how tabbed navigation worked in Prism for Xamarin.Forms 6.3.
Prism 6.3 Behavior
NavigateAsync(“TabbedPage/ViewA/ViewB”) will navigate to the TabbedPage, and if ViewA is a tab that is defined within the TabbedPage, the ViewA tab would be seelcted and then continue navigating to VIewB. If ViewA does not exist as a tab, then you will continue to navigate as expected with ViewA being created and added to the navigation stack.
NavigateAsync(“TabbedPage/NavigationPage/ViewA/ViewB”) would search the TabbedPage for the first instance of a tab that was a NavigationPage, then navigate within the Navigation page the remaining ViewA and ViewB pages. This provided the ability to deep link into a tab’s nested navigation page, but there was no way to opt-out of this behavior. Plus, if you had more than one NavigationPage it would just use the first instance it found and you couldn’t control which one to use.
Also, the INavigationAware methods did not get called to all tabs meaning that you would be responsible for forwarding any parameters to all your tabs.
New and Improved 7.0 Behavior
NavigateAsync(“TabbedPage/ViewA/ViewB”) will no longer select any tabs, but rather continue processing the navigation as separate pages on the navigation stack.
If you wish to select a tab, you will now use a parameter called “selectedTab” to indicate which tab you would like to select.
NavigateAsync(“TabbedPage?selectedTab=MiddleTab/ViewA/ViewB”)
This will navigate to the TabbedPage, selected the “MiddleTab” and continue navigating ViewA and ViewB onto the navigation stack.
For tabs that are wrapped inside a NavigationPage, you do not need to change anything. The syntax is the same. This will search each tab to see if it is a navigation page and if the CurrentPage of the NavigationPage matches “MiddleTab”, the tab will be selected. This is much more flexible than the existing behavior as before it would take the first instance of the NavigationPage found. Now you can choose which tab exactly.
There is a constant in the KnownNavigationParameters called SelectedTab that you can use instead of a string.
NavigateAsync($”TabbedPage?{KnownNavigationParameters.SelectedTab}=MiddleTab”)
Now you may be asking about the INavigationAware methods. How do these work with the new TabbedPage navigation behavior. Well, this is how it works:
- OnNavigatingTo will be invoked on the TabbedPage and ALL TABS.
- OnNavigatedTo will be invoked on the TabbedPage and only the SELECTED TAB.
- OnNavigatedFrom will be invoked on the TabbedPage and only the SELECTED TAB.
Note: the parameter key selectedTab is now a reserved parameter name. Similar to a reserved keyword in C#. If you use this in your app as a key, you may experience undesired behavior.
Note: At this time there is no native support for deep linking into a Tab that is a navigation page. Please let me know if you need this functionality.
Container Updates – (Breaking)
Beside the changes we made in Prism, we also inherited some breaking changes from the DI containers that we support. Notable Unity an Ninject are our problem containers.
- Unity 5 was recently released and had a massive API break. If you use Unity, all your namespaces are now broken. A simple find and replace should fix it, but it’s still something that you shouldn’t blame on us. We aren’t taking responsibility for that one.
- Ninject doesn’t work on iOS or Android. So guess what? We have to completely drop support for it. You will no longer be able to use Ninject until the project maintainers decide to do the work necessary to make it work with iOS and Android. Be sure to let me know when that happens.
Other Notable Breaking Changes
Here are some other breaking changes that you may be using that you should be aware of.
- Removed DependencyService auto-resolution – in previous versions of Prism, if you used the Xamarin.Forms Dependency attribute on your platform specific services, Prism would automatically resolve them when asked for in the ctor. Now, we have removed this feature and when you run your app, it will break. It is recommended that you register your services with the IPlatformInitializer instead. You can also continue to use the IDependencyService that is a wrapper around Xamarin’s DependencyService API.
- Renamed IApplicationLifecycle to IApplicationLifecycleAware – this was made just to align the naming convention with our other interfaces
- ObservesCanExecute breaking change – we have simplified the signature for the ObservesCanExecute method to no longer provide the VM object in the delegate
- Old (v6.3): ObservesCanExcute((**vm**) => Property)
- New (v7.0): ObservesCanExecute(() => Property)
- RegisterTypeForNavigation renamed to RegisterForNavigation – I already covered this briefly, but thought I would mention it again.
New Features
Wow…. now that I wrote them all down, that is a crap load of braking changes. This is going to be a frustrating update, and I’m so sorry about that. However, I think you can see why these changes were made as they enbled us to implement a ton of new features. For now I wil just list them out because this post is long enough already. I do plan on blogging about each one of these new features in more detail as soon as I have time. For now, here is the short version.
Dynamic Tab Generation
You can now dynamically create tabs when navigating to a TabbedPage by using the KnownNavigationParameters.CreateTab constant or by using the “createTab” parameter name.
_navigationService.NavigateAsync(“MyTabbedPage?createTab=ViewA&createTab=ViewB”);
This will create a TabbedPage and then create two tabs, ViewA and ViewB.
To create a tab that wraps a page in a NavigationPage, simply denote this as a nested hierarchy using the | character.
_navigationService.NavigateAsync(“MyTabbedPage?createTab=NavigationPage|ViewA”);
Remove Pages from Navigation stack ../
This feature allows you to remove pages form the navigation stack of a NavigationPage while at the same time navigating to a new page. For each page you wish to remove, prefix your navigation path with ../.
Example
Our app requires a user to login in order to edit “User” profile information. This will require the user to be prompted to login and then once successful continue to edit the profile. This leaves us with the following navigation stack:
“NavigationPage/UserList/UserDetails/LoginPage/EditUser”
If we were to hit the back button from the EditUser page, we would be returned to the LoginPage. This is not the desired experience. Instead, we want to go back to the UserDetails which was just updated. To achieve this we provide the following navigation URI from the LoginPage page with a successful login attempt.
NavigationService.NavigateAsync(“../EditUser”);
This would remove the LoginPage and then immediately navigate to the “EditUser” page which we now have access to.
You can chain the ../ instruction for each page that needs to be removed from the stack.
Given: “NavigationPage/ViewA/ViewB/ViewC/ViewD”
Navigate from ViewD with: NavigationService.NavigateAsync(“../../../ViewE”);
Results in: “NavigationPage/ViewA/ViewE”
Note: This only works when navigating within a NavigationPage! Modal pages are not supported.
UseModalNavigatoin in Deeplinks
You can now control the various segments of a deep ink by setting the useModalNavigation parameter on any specific navigation segment in the URI.
NavigatAsync(“NavigationPage/ViewA/ViewB/NavigationPage?useModalNavigation=true/ViewC/ViewD”);
You can also use the built-in constant KnownNavigationParameters.UseModalNavigation
NavigatAsync($”NavigationPage/ViewA/ViewB/NavigationPage? {KnownNavigationParameters.UseModalNavigation} =true/ViewC/ViewD”);
Note: the parameter key useModalNavigation is now a reserved parameter name. Similar to a reserved keyword in C#. If you use this in your app as a key, you may experience undesired behavior.
INavigationService.GoBackToRoot
If you are within a NavigationPage, you can now clear all pages except the root page off the navigating stack by calling INavigationService.GoBackToRootAsync. This is equivalent to calling Xamarin.Forms Navigation.PopToRoot method.
Retrieve current navigation URI
You can now get the absolute navigation path of a page by calling INavigationService.GetNavigationUriPath.
There may be some edge cases that I may have missed but so far it works with the most complex navigation stacks I have tried.
The only scenario that I know is not supported is any type of navigation stack in which you are nested inside a NavigationPage which is a child of a Tab inside a TabbedPage. Also, if you have a page type registered twice for navigation, but with different names, the first registration will be used.
ObservesProperty Complex Property Support
I’m really excited about this one. People have been asking for this for a long time and thanks to a great PR from the community, you can now observe complex properties for change notifications.
Example:
ObservesProperty(() => Property.NestedProperty.NestedPoperty)
Summary
Wow! That is a lot! I mean a freaking crap load of changes and features. Hell, I didn’t even mention the other 35 bug fixes and enhancements. For that, you should just go check out the release notes.
Thank you for being so patient with me over this last 10 months. I know you have been waiting a long time for a lot of the new features, and most of you were using the previews or nightly builds in order to get them.
A big thank you to the community for all their time and effort helping us test and implement all these changes.
A huge thank you to Dan Siegel. Without him, I would still be working on this release and way behind. I really couldn’t have done it without him. He started with a single PR, became more involved over time, and soon became one of the core team members. His contributions are invaluable to me, to Prism, and to the community. Not only has he become a great team member, but a great friend. Thank you Dan.
As always, big releases like this make me nervous. Even with all the test coverage we have, there is always something that pops up that we didn’t foresee, or Xamarin broke again. If you find any issues, please let us know over on the Prism Library GitHub site. Now we have a ton of docs to write and even more samples to help everyone understand all these changes.
Feel free contact me on my blog, connect with me on Twitter (@brianlagunas), or leave a comment below for any questions or comments you may have. Better yet, be sure to reach out to Dan on twitter as well (@danjsiegel).
Hi Brian , can you please explain how we get the IContainerProvider in a view model. I tried to replace the code container with IContainerProvider in one of the view models. I get an error –
Exception is: InvalidOperationException – The current type, Prism.Ioc.IContainerProvider, is an interface and cannot be constructed. Are you missing a type mapping?
How are we supposed to map that for dependency injection?
You shouldn’t need to access the IContainerProvider in any ViewModel. Any dependencies you need should be injected into the ctor of the ViewModel. It is not recommended to resolve dependencies via the container from within the ViewModel directly.
If you must absolutely do this, which I don’t recommend and why t’s not there by default, simply register the Container property in the App.cs with the IContainerProvider interface. So use the RegisterInstance method in RegisterTypes.
I might be missing something basic but I can’t get the figure out the how to resolve it from IContainerProvider? Can you please share a code sample?
Just register it like you would anything else. In App.xaml.cs RegisterTypes method
containerRegistery.RegisterInstance[IContainerProvider](Container);
Then you can ask for it in your VM ctor.Hi Brian,
Good job for this. Prism is great.
I try to add a content view named “Slider” into a page named “TestPage”. I added ViewModelLocator.AutowireViewModel=”True” in the XAML of my content view (Slider.xaml). If the constructor of SliderViewModel has no parameter everything work but if I had some parameter to the constructor of SliderViewModel (IEventAggregator, INavigationService, ILoggerFacade) the application crash : Object reference not set to an instance of an object and the SliderViewModel is not initialized. The TestPage.xaml have also AutowireViewModel. The constructor of TestPageViewModel have 3 parameters (IEventAggregator, INavigationService, ILoggerFacade) which are well injected.
Do you know why there is a crash on the SliderViewModel with parameters on the constructor ?
This happens because you are defining the ContentView in XAML and the container is not resolving it. Also, I’m not sure the AVM attached property will work with a ContextView. This is not an officially supported scenario.
Can I just give two claps for ObservesProperty Complex Property Support! Thanks Brian.
You’re welcome!
Hi Brian,
I am just starting a new project, mostly greenfield.
The tool I want to develop will interact with some windows only software.
So I currently plan to use WPF for the new project.
I like to use Prism 7.0.
So when will Prism 7.0 for WPF be finished?
I saw the milestone “Prism 7.0 for WPF” but no due date.
Regards
Vasco
There is no time frame on the release of Prism for WPF v7.0. It will be released when I have time to finish it.
Doesn’t look like the documentation is updated (e.g. link below)? Or is there a different spot for it? Please let us know, thanks. http://prismlibrary.github.io/docs/xamarin-forms/Dependency-Service.html
Docs aren’t updated yet. We would appreciate the help if you wanted to submit a PR.
Hi Brian
I has added prism 7 to my project and I want navigate inside ViewModel code but when I add as parameter (INavigationService navigationService) and run it appear this message “Default constructor not found for type notes_xform.ViewModels.ListNotesViewModel”. How I can fix this problem?
Sorry, there is not enough information provided. This is better asked on StackOverflow.
If I use NavigationService to add to the stack more than 1 page, e.g. call NavigateAsync to “TestPage1/TestPage2/TestPage3” from my MainPage (a NavigationPage), only the first page will still be a NavigationPage and have the back button – is this the intended behavior?
Sorry tried to Reply to the comment but it didn’t work; forgot to clarify that this is when the page I’m navigating away from is a CarouselPage. That is what seems to throw things off.
I won’t post any more questions here, will go to StackOverflow. In meantime, in case it helps anybody, I jotted down some notes to help get started with Navigation in Prism in case it’s helpful for anybody: https://gist.github.com/mzhukovs/58c2134a40825a232a249dda91b59ec3. Really great stuff, love everything about how the templates are set up and all the built-in features that I’ve had to do manually in the past. Thanks to you and all the project owners.
Brian – much appreciation for all the work you put into Prism with your colleagues. I am relatively new to Xamarin and Prism but I have a pretty decent little app running with Xamarin.Forms and Prism.
That being said, I have to say the upgrade process is painful! I find that for every “major” upgrade it ends up being easier for me to just create a brand new project from the templates and then put “my stuff” back into the new template. This seems to be the only way of getting my app to run with the new releases.
Is this normal? Again, my app is small and I can usually get up an running in a couple of days. But trying to fix all the broken pieces and updates and references, etc. … I’m going on 7 days now and I’m thinking I should just start over.
Is this normal? Do I just suck it up? Any recommendations? Again, not the fault of your work or Xamarin’s … just upgrading is becoming quite daunting.
Keep in mind a Major release does indicate breaking changes. The breaking changes are easy to fix as long as you know what you’re looking for. Most are find and replace issues. The other are slight changes to interfaces which VS will help you fix. What’s important is that you read the release notes so you know what to look for. Just about every break is an API break which will result in a build error with a lot of red underlines to point you in the right direction. Read the release notes (we document everything that is broken and needs to be fixed) and use VS intellisense to help you figure out the rest if you don’t understand what exactly is broken.
Good luck
Hi Brian,
Thanks for all your work for Prism. It is greatly appreciated.
Microsoft finally released a quick start guide for WPF for Xamarin Forms (https://docs.microsoft.com/en-us/xamarin/xamarin-forms/platform/wpf). We have multiple applications built with Xamarin Forms utilizing Prism 7. We also utilize Infragistics controls. We have a lot of potential clients asking us for a WPF version of our app for Windows 7. I was wondering if you could provide any guidance on timeline and guidance on how and when Prism and the Infragistics controls would be available with WPF and Prism.
thanks,
Grant
Prism for Xamarin.Forms will not support WPF in XF. Infragistics also does not plan on supporting WPF within the scope of XF. WPF was added to XF by the community and is not officially supported by Xamarin. Xamarin does not have any immediate plans on moving it forward. If you want to have a WPF app, I would recommend not using XF for that, but rather create an actual WPF project and share your logic across platforms.
Sweet Changes.
Thanks for keeping this project up to date 🙂
Since CreateLogger() was removed – to to hook to the Prism-events (like when a module is loaded, etc.)?
You just register your logger with the container instead of using a method to do it.
Hi Brian!
I’m using Prism and almost finishing my project with it, but just now (my fault) I’ve realized that everytime I call another page from master detail, the OnNavigatedTo is being called twice, I’m not using tabbed page, just master detail, and I have no idea why it is happening,
heres my question in StackOverFlow, Can u help me with that plz? I’m searching for this everywhere and I didn’t find any answer.
https://stackoverflow.com/questions/50254146/xamarin-forms-prism-onnavigatedto-calling-twice