Just over 2 months ago I released the first preview of the new Prism for Xamarin.Forms. Since then, I have been hard at work gathering community feedback, refactoring the code base, and implementing new features. Today I am happy to announce the next preview version of Prism for Xamarin.Forms 5.7.0 is now available on NuGet now.
Let’s take a quick look at the newest improvements and features added to Prism for Xamarin.Forms.
Navigation Improvements
The first improvement I have made is related to how we obtain the correct INavigationService in our ViewModels for navigation. In 5.6.1, you had to have your ViewModel implement the INavigationServiceAware interface. This interface defined a single NavigationService property that would be set during the creation of the ViewModel.
Old:
{
public INavigationService NavigationService { get; set; }
}
Well, this worked and all, but really isn’t the ideal way to get the NavigationService. While using INavigationServiceAware enabled you to keep your ViewModels testable, it would hide the dependencies of the ViewModel. Which means, you had to have knowledge of the interface and the dependency on the NavigationSrvice property in order to properly test. This is not what we want.
Breaking Change: INavigationServiceAware has been removed.
Now, with Prism for Xamarin.Forms 5.7.0, you can now inject the INavigationService directly into the constructor of your ViewModels.
Important: In order for Prism to inject the proper INavigationService via the constructor, you must name the parameter “navigationService”.
New:
{
_navigationService = navigationService;
}
Now, this is much better. We are now completely testable and the dependencies of our ViewModels are known based on the constructor signature.
The next improvement I made was to how you register your types for navigation as well as how you navigate to them. I have added an overload for IUnityContainer.RegisterTypeForNavigation which now accepts two types in the generic signature. The first argument is for the View Type, the second argument is of a Class Type, most likely a ViewModel.
There was also a corresponding change made to the INavigationService.Navigate method to accept a generic in place of a string to identify the View to navigate to. This will be useful for those devs that like to eliminate those nasty magic strings, and conceptually navigate to ViewModels instead.
DepedencyService Improvements
If you have ever used the Xamarin.Forms DependencyService, you have probably beaten your head against the wall trying to test your ViewModels that make a call to it. What’s so bad about it? You have to make a static method call off of the DependencyService class. This is no good, especially for those of you who like to write testable ViewModels.
Old:
{
_textToSpeech = DependencyService.Get<ITextToSpeech>();
SpeakCommand = new DelegateCommand(Speak);
}
private void Speak()
{
_textToSpeech.Speak(TextToSay);
}
You might be asking yourself, “so how does Prism improve this experience?”. Well, I’m glad you asked, because I am about to blow your mind, as well as make your development and testing life much easier. You can now ask for your dependency as an argument in your ViewModel constructor. You heard me! Just ask for it, and Prism will give it to you. You don’t have to do anything special. It just works!
New:
{
_textToSpeech = textToSpeech;
SpeakCommand = new DelegateCommand(Speak);
}
private void Speak()
{
_textToSpeech.Speak(TextToSay);
}
As long as you have done the necessary steps to register your platform specific services with Xamarin.Forms DependencyService, then it will just work with no extra code from you. Actually, it eliminates code you would have normally had to write. Check out this sample app that demonstrates how it works using the ITextToSpeech sample provided by Xamarin.
Well, that does it for this post. I hope you enjoy these new features and like the direction Prism for Xamarin.Forms is going. As always, 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.
Great work. Looks similar to another framework I know 🙂
Any reason why you have to name the parameter ‘navigationService’. Shouldn’t matter what you call it so long as it’s registered it will be injected surely.
As you are aware, navigation in XF depends on a Pages INavigation to function properly. So, I can’t just register a global, singleton, navigation service to rule them all. I have to have a navigation service specific to each page and ViewModel. Since I am using a DI container to resolve this service through constructor injection, I have to provide a parameter override before resolving the ViewModel requesting the navigation service. This means I have to look for a specific name, in this case “navigationService”, because Unity doesn’t allow me to just look for a type (that I know of). I hope this makes sense.
There’s no reason why you still can’t have a singleton NavigationService which as able to resolve the current page Navigation instance. I do this by injectiing in Func and then registering this with a resolver method to give me the current page Navigation object. Alternatively you could just get the NavigationService to keep track of the current page since it is resposible for pushing and popping them.
I’ve considered having the NavigationServcie maintaining it’s own stack of pages for this reason, but I haven’t really got into the details of this. There are some scenarios, such as tabbed pages, in which the NavigationService wouldn’t work reliably if I used that approach too. I have some concerns with managing objects and avoiding memory leaks. I’m not sure the resolver approach would be reliable in Prism’s architecture, though I would have to look into it to be sure. I will say, pull requests are always welcome 🙂
Great work Brain (and team)!
We have been using Prism before there was Xamarin.Forms (in plain Windows Store Apps). And I really like the fact that we can use the same concepts again in Xamarin.Forms: Unity, Navigation, AutoWireViewModels, etc. Your last improvement with “RegisterTypeForNavigation” makes it so much easier to navigate between ViewModels and keep the code-behind of our views clean. Nice!
We have one small issue that I haven’t figured out yet: I’m looking for a place to do some bootstrapper stuff (like creating a SQLite database) before the app starts. The best I’ve come up with is placing it in the override of the CreateMainPage of the UnityBootStrapper. Any advice on that?
Thanks a lot! And please keep up the good work!
Thanks for the kind words. We have been working hard and we have greatly improved the navigation service in the latest repo code base. I’ll be pushing NuGet updates soon.
Anyways, back to your question. If you don’t need any of the services or need access to the container at the time, you could override the Run method, do your DB code prior to calling base.Run(); Let me know if that would work.
Good suggestion about overriding the Run method. That will work! I hope I’ll remember how to use the new keyword 😉