For a while, I have been thinking about what should I write next. In my mind, there were two ways how to get it done. Either I can treat it like I’ve wanted to, so first log entry would appear, or write something from the scratch. I think that it will be better (for you) if I write a blog about the project which is about to start then writing about something that already exists. But then something changed. I received an email from a potential client asking me to estimate the price of an app, he wants to do. After that, almost everything got clear (almost). I’ve planned the nearest posts which will be written in here. So here is the plan. In this post, I am going to write about NavigationService in Xamarin.Forms using Autofac. In the next one, I will share my knowledge (still learning!) about estimating an app when you are a newbie. Later (if a client agrees to my contract conditions), I will start a series of posts about the new, and the whole process of creating it. If the client doesn’t agree and the project is not going to start, then I’ll figure another plan or I’ll try to find a new client 😉 Of course, I won’t stop with my logbook so everything is gonna be mixed all together.
Coming back to this post topic: NavigationService. Let’s start from the beginning. The first “big” project I was put into was a mobile app written in Xamarin.Android. It was quite an easy app, but I was a newbie in the mobile world. Fortunately for me, I met quite a good team, which had some knowledge about MVVM. So I started working on a mobile app, in Xamarin.Android using MVVM Cross. Of course, at the beginning, I was like crafting the code. “You should put business logic in ViewModels, UI’s in Views, everything else in other layers”. Ok, I was like a monkey doing what they told me to do. After a time I can say that I’ve done some pretty bad things like showing Toast from ViewModel or even from DB layer. But who cares when it is working? Here I come to the point. At one moment I’ve decided to get more self-aware of things I am doing. I’ve started digging into MVVM. Now, I know why we should separate all these layers, what is the purpose of doing it & finally, I’ve learned that we should not show “Toast” from ViewModel.
But as I was knowing more, I started to think: what about navigation? Should it be a part of ViewModel’s logic? In one of the previous companies I was working for, we were using normal Xamarin.Forms Navigation in ViewModel layer. At that time I was already thinking this is kind of an inappropriate way to get it done. Probably you already know IT word works. There is no time for refactoring because there are tasks with higher priority, and we need to meet the deadline.
I knew it was bad but didn’t have a chance to fix it. After all, I’d changed the company, received my own project and I could have done whatever I wanted. So, I decided to use MVVM but this time I was willing to do it in a proper way. Sorry, too long introduction. Let’s cut the rest of it…
I’ve implemented my own NavigationService using Autofac.
First, we need to think what methods exactly do we want. In my use case I needed NavigateTo method, GoBack. After thinking about the solution, I decided to implement also the method RegisterPage.
What were the requirements?
- The navigation service should be implemented as a singleton. Only one instance at a time.
- We should be able to navigate to a page by passing the string (in my opinion ViewModel shouldn’t even know in which class is the View implemented, so passing whatever-string-you-want is better option),
- We should be able to inject this service into ViewModels,
- We should be able to register pages,
- We should be able to pass parameters to page.
That’s all of the requirements so let’s start with code. Firstly, I implemented the INavigationService interface:
Then I implemented this interface in a NavigationService:
- RegisterPage(string pageKey, Type pageType) — this is a method which allows us to register page for navigation. This just simply means that it will be added to dictionary in which we will store all the pages. Page key is the key which we will use later when navigating to this page.
- NavigateTo(string pageKey, bool animated = true) — this method will be used to navigate to pages with no parameters.
- NavigateTo(string pageKey, boolanimated=true,params( string propertyName, object param) args) — this method will be used for navigating to pages with constructor accepting params. I used the Tuple in here (if you want to use it then install package System.Tuple). I decided it to it this way, cause, in my opinion, it is just batter to pass a parameter with description what is this parameter). We should still remember View knows something about ViewModel, so can easily adapt its constructor.
- GoBack() — nothing to say in here. Just PopAsync
- PrivateNavigateTo(Page page,bool animated=true)–this is just the method that does the navigation, other two methods are just for retrieving the View object.
Having both implemented we can go to our Autofac ServicesModule and register our Service
In my App.xaml.cs file I have a method ConfigurePages() which has all of the pages registered for navigation. Then in NewsViewModel I have other two methods (see below)
Pros and cons
I know that this solution is not perfect. In few points, I will state the pros and the cons of it.
• We do not violate MVVM rules when using this Service.
• We have a NavigationService we can use wherever we want.
- In NavigationService we are using a reference to the static field Application.Current.MainPage. I hate statics and this is a little problem for me.
- We are using a reference to our Container. It will be much better if I skip this static fields Current and somehow get access to Container to resolve object with param constructor. I will think about it — don’t have time because the deadline is coming… 🙂
- Lacking possibility to show a pop-up with this service — (also, will add this functionality in future)
Hope that everything is clear and understandable. If not, then please don’t hesitate to contact me. If be any chance you find a bug, then please tell me.