MVVM and NavigationService

One of the many benefits of implementing any template is the separation of problems between different levels in the application. In the case of Silverlight and MVVM, I believe that NavigationService belongs to the user interface.

If the NavigationService belongs to the user interface, it should be used in the XAML code behind, but the commands are executed in the ViewModel. Should I raise an event in Command in the ViewModel and allow View to handle the event and trigger the navigation? It sounds a little absurd if all I do is just go to another page. Shouldn't I just handle the UI event directly and move from there?

View control event β†’ ViewModel command β†’ Raise event β†’ View Processed event β†’ Navigation

or

View management events β†’ View processed event β†’ Navigation

+4
source share
2 answers

There are two documented approaches to this problem.

  • Implementing Navigation Using MVVM Light Messing Features

    This approach was suggested by Jess Liberty in Part 3 , his MVVM Ligtht soup for the Series Nuts. His approach is to send a message from a command to a view indicating that a navigation operation should be performed.

  • ViewService implementation that handles navigation

    This approach was Laurent Bugnion's response to Jesse's post. This implements a service that handles all navigation operations invoked by view models.

Both approaches relate only to navigation in WP7 applications. However, they can also be adapted to Silverligt applications.

Jesse's approach is easier to use in SL since it does not require access to the root visual. However, the navigation code is distributed in several places and requires code to perform the actual navigation.

Laurent's approach requires access to the root visual object, which is used to access the built-in navigation features. Gaining access to this, as shown in the Laurent code, doesn't really matter in WP7 applications. However, in SL applications, this is a bit more complicated, since there is no environment frame. However, as I expected, I used the template for SL in one of my projects, using an attached property that performs the required wiring, so although it takes more work, it can also be used for SL.

So the conclusion is that although Jesse's approach is easier to implement, I personally prefer the Laurent approach, because it is a cleaner architecture - there is no necessary code, and the functionality is encapsulated in a separate component and, thus, is at one point.

+6
source

A bit late to this issue, but it is relevant and, I hope, will benefit someone. I had to create an SL4 application with MvvmLight and wanted to use a wrapper for the navigation service that was mock-up and could be introduced into the ViewModel. I found a good starting point here: Laurent Bugnion SL4 trial code examples from Mix11, which includes a demo of a navigation service: Deep Dive MVVM Mix11

Here are the main parts for implementing a breadboard navigation service that can be used with Silverlight 4. The key problem is getting a link to the main navigation frame that will be used in the custom NavigationService class.

1) In MainPage.xaml, the navigation frame is given a unique name, for this example there will be a ContentFrame:

<navigation:Frame x:Name="ContentFrame" Style="{StaticResource ContentFrameStyle}" Source="/Home" Navigated="ContentFrame_Navigated" NavigationFailed="ContentFrame_NavigationFailed"> <!-- UriMappers here --> </navigation:Frame> 

2) In MainPage.xaml.cs, the navigation frame is displayed as a property:

 public Frame NavigationFrame { get { return ContentFrame; } } 

3) The navigation service class implements the INavigationService interface and relies on the NavigationFrame property MainPage.xaml.cs to get a link to the navigation frame:

 public interface INavigationService { event NavigatingCancelEventHandler Navigating; void NavigateTo(Uri uri); void GoBack(); } public class NavigationService : INavigationService { private Frame _mainFrame; public event NavigatingCancelEventHandler Navigating; public void NavigateTo(Uri pageUri) { if (EnsureMainFrame()) _mainFrame.Navigate(pageUri); } public void GoBack() { if (EnsureMainFrame() && _mainFrame.CanGoBack) _mainFrame.GoBack(); } private bool EnsureMainFrame() { if (_mainFrame != null) return true; var mainPage = (Application.Current.RootVisual as MainPage); if (mainPage != null) { // **** Here is the reference to the navigation frame exposed earlier in steps 1,2 _mainFrame = mainPage.NavigationFrame; if (_mainFrame != null) { // Could be null if the app runs inside a design tool _mainFrame.Navigating += (s, e) => { if (Navigating != null) { Navigating(s, e); } }; return true; } } return false; } } 
0
source

Source: https://habr.com/ru/post/1391048/


All Articles