Navigation in MVVM: a (un)solved problem (part 1)
Join the DZone community and get the full member experience.
Join For FreeThis is first post in the series describing the navigation pattern in XAML based application. The series will focus on problems and solutions that arise when using MVVM (Model-View-ViewModel) and XAML. Even though they are meant to be used together, the MVVM pattern does not solve navigation completely nor correctly.
WPF and Silverlight: introduction
Windows Presentation Foundation was introduced almost 10 years ago. Besides introducing a new and beautiful way of creating UI declaratively, it also introduced a new pattern based on the powerful data binding mechanism: MVVM. Since it was born on desktop, WPF applications consisted of windows and dialogs.
A few years later we got Silverlight: a version of WPF (also known as WPF/E where E stands for everywhere) trimmed down and optimized for the web. Due to its architecture and the fact it was used in browsers, it also introduced a navigation stack and navigation capabilities. Its primary purpose was mimicking how browsers navigate from one page to another. The Frame
contained Pages
and navigation was done through (mapped) URIs. Using URIs for navigation had one serious implication: when navigating from one page to another, you could only send strings, or objects that can be converted to strings, through the query string.
Windows Phone
Windows Phone 7 was based on Silverlight and navigation model was simply ported over. The concept of pages translated really well to mobile devices, it was far superior than windows and dialogs concepts used on the desktop. But reusing the navigation logic based on URIs introduces a whole set of problems.
Let’s take a look at the typical navigation in Silverlight for Windows Phone:
NavigationService.Navigate(new Uri("/SecondPage.xaml", UriKind.Relative));
NavigationService
is present in all pages and is used for navigation. It is possible to get it from the static Application.Current
object though, although pages are the first class objects in navigation concepts. The major problem in the example above is using URIs and physical file locations for navigation. Even though it is possible to use UriMapper
to map keywords like "SecondPage"
to the actual physical paths, we still have problems with occasional types and inability to move files around the same or multiple projects.
And as for passing arguments, the limitation is still present and objects cannot be passed when navigating to another page.
Finally, with the current setup, it is impossible to either know when the navigation completes or when the navigation will return back (in case we are implementing our own pickers or choosers). For that we need to turn to the master object for navigation: the Frame
itself.
WinRT
WinRT is a completely new platform for building mobile applications for a variety of platforms. However, it alters the built in navigation slightly. Instead of navigating to physical pages on the file system, it takes the type of the destination page.
Frame.Navigate(typeof (SecondPage));
Since it allows sending arbitrary objects as parameters, the approach taken by the WinRT team solves three biggest problems when compared with the Silverlight version: file organization, typos and passing arguments.
However, it still does not provide indication of success nor does it allow for “waiting” for navigation to come back.
Xamarin.Forms
The latest kid in the block is Xamarin.Forms – a XAML based framework for building cross-platform applications. It also features a navigation stack, but it is based on concrete objects instead of types or URIs. When navigating, the destination page is passed as a parameter. This is both type safe and it allows passing arbitrary parameters.
Here is an example showing navigation in Xamarin.Forms:
await Application.Current.MainPage.Navigation.PushAsync(new SecondPage { BindingContext = new SecondPageViewModel });
Since the methods for navigation are asynchronous, this allows the caller to know once the navigation completes. Xamarin.Forms also introduce concept of modal pages. These pages are not featured on the same stack as regular pages and they are pushed/popped via different methods than regular pages.
MVVM and navigation
Navigation is extremely coupled with the view layer and all application logic is placed in the view model layer. Adding into account the complex application lifecycle found on mobile platforms, injecting navigation into the view model introduces a couple of problems.
First problem is the design of so called navigation service that will provide navigation in the view model layer. One solution is to provide an interface that will, depending on the platform, simply abstract the underlying mechanism of the target platform. In Silverlight we have INavigationService
which takes URIs for navigation, in WinRT we have strongly typed navigation service while Xamarin.Forms already provides useful INavigation
interface.
However, this approach is wrong and violates the MVVM principle. View models should not have information about the target view, this is clearly an example of a leaky abstraction. No matter what initiated the navigation, view models should not be aware of the target view.
MVVM Light introduced INavigationService
in the last major version. It uses a key-based configuration and view models navigate using keys which are simple strings. This removes the “knowledge” view models have about the destination view and acts as a URI mapper. Better approach than simply reusing platform concepts, but falls short on some other.
Other approaches include using messaging for navigation – clearly problematic since messages are broadcasted to multiple subscribers. Caliburn.Micro introduces a completely different paradigm for building applications which also suffers from the same problems as the other solutions.
In the next post we’ll take a look at how navigation and lifecycle events fit into MVVM pattern.
Published at DZone with permission of Toni Petrina, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Trending
-
Microservices With Apache Camel and Quarkus
-
RBAC With API Gateway and Open Policy Agent (OPA)
-
Comparing Cloud Hosting vs. Self Hosting
-
How To Approach Java, Databases, and SQL [Video]
Comments