Sharing Code: Adding NavigationService





5.00/5 (1 vote)
An example about NavigationService in share code scenarios, that will be registered in one IOC container and injected by the view model’s constructor.
Introduction
This sample has the goal to show an example about NavigationService
in share code scenarios, that will be registered in one IOC container and injected by the view model’s constructor. The idea is to have an INavigationService
interface that is portable and used in portable view models, that in practice will have different implementation in the platform project.
The source code can be got from here.
Building the Sample
You only need Visual Studio 2012 and Windows 8, both the RTM version.
Description
Before starting the sample, I recommend to see the related samples that was created:
- Consuming Odata Service in Windows Store Apps (Include MVVM Pattern)
- Creating portable code in Windows Store Apps (PCL + MVVM + OData Services)
- Sharing Code between Windows Store and Windows Phone App (PCL + MVVM + OData)
In this moment, we have a TitlesPage.xaml in both projects and in this sample, we will create a second page called TitleDetailsPage.xaml and implementation for navigating between them and passing parameters.
Let’s start!
The main points are:
- INavigationService
- NavigationService in Windows Store Apps
- NavigationService in Windows Phone Apps
- Others details
1. INavigationService
Navigation is a very important point in one application, because it allow us to switch between pages and in some cases, sends data between them. There are some points to analyze:
- In Windows Store app, we navigate to type of the page that is an object and in Windows Phone apps, we navigate to URI using the
string
name of the page. - For passing a parameter, we can send an object in a Windows Store app, but for Windows Phone apps we need to create a query
string
with the parameter. - More common features are the
CanGoBack
property andGoBack
method.
In general, the for navigation must have:
- Navigation method (that allow parameters)
GoBack
methodCanGoBack
property
Another “little problem” is the fact in portable class libraries, I cannot use the page type, and a solution for it is to navigate for the ViewModel
that will be used in the next page. With this, my INvaigationService
could be:
/// <summary>
/// The NavigationService interface.
/// </summary>
public interface INavigationService
{
/// <summary>
/// Gets a value indicating whether can go back.
/// </summary>
bool CanGoBack { get; }
/// <summary>
/// The go back.
/// </summary>
void GoBack();
/// <summary>
/// The navigate.
/// </summary>
/// <param name="parameter">
/// The parameter.
/// </param>
/// <typeparam name="TDestinationViewModel">
/// The destination view model.
/// </typeparam>
void Navigate<TDestinationViewModel>(object parameter = null);
}
Let’s see how it will be implemented in Windows Store apps.
2. NavigationService in Windows Store Apps
/// <summary>
/// The navigation service.
/// </summary>
public class NavigationService : INavigationService
{
/// <summary>
/// The view model routing.
/// </summary>
private static readonly IDictionary<Type, Type> ViewModelRouting = new Dictionary<Type, Type>()
{
{
typeof(TitlesViewModel), typeof(TitlesPage)
},
{
typeof(TitleDetailsViewModel), typeof(TitleDetailsPage)
}
};
/// <summary>
/// Gets a value indicating whether can go back.
/// </summary>
public bool CanGoBack
{
get
{
return RootFrame.CanGoBack;
}
}
/// <summary>
/// Gets the root frame.
/// </summary>
private static Frame RootFrame
{
get { return Window.Current.Content as Frame; }
}
/// <summary>
/// The go back.
/// </summary>
public void GoBack()
{
RootFrame.GoBack();
}
/// <summary>
/// Navigates the specified parameter.
/// </summary>
/// <typeparam name="TDestinationViewModel">
/// The type of the destination view model.
/// </typeparam>
/// <param name="parameter">
/// The parameter.
/// </param>
public void Navigate<TDestinationViewModel>(object parameter)
{
var dest = ViewModelRouting[typeof(TDestinationViewModel)];
RootFrame.Navigate(dest, parameter);
}
}
3. NavigationService in Windows Phone Apps
The implementation for the Windows phone could be something like the following code:
/// <summary>
/// The navigation service.
/// </summary>
public class NavigationService : INavigationService
{
/// <summary>
/// The view model routing.
/// </summary>
private static readonly Dictionary<Type, string> ViewModelRouting = new Dictionary<Type, string>
{
{
typeof(TitlesViewModel), "View/TitlesPage.xaml"
},
{
typeof(TitleDetailsViewModel), "View/TitleDetailsPage.xaml"
}
};
/// <summary>
/// Gets a value indicating whether can go back.
/// </summary>
public bool CanGoBack
{
get
{
return RootFrame.CanGoBack;
}
}
/// <summary>
/// Gets the root frame.
/// </summary>
private Frame RootFrame
{
get { return Application.Current.RootVisual as Frame; }
}
/// <summary>
/// Decodes the navigation parameter.
/// </summary>
/// <typeparam name="TJson">The type of the json.</typeparam>
/// <param name="context">The context.</param>
/// <returns>The json result.</returns>
public static TJson DecodeNavigationParameter<TJson>(NavigationContext context)
{
if (context.QueryString.ContainsKey("param"))
{
var param = context.QueryString["param"];
return string.IsNullOrWhiteSpace(param) ? default(TJson) :
JsonConvert.DeserializeObject<TJson>(param);
}
throw new KeyNotFoundException();
}
/// <summary>
/// The go back.
/// </summary>
public void GoBack()
{
RootFrame.GoBack();
}
/// <summary>
/// Navigates the specified parameter.
/// </summary>
/// <typeparam name="TDestinationViewModel">The type of the destination view model.</typeparam>
/// <param name="parameter">The parameter.</param>
public void Navigate<TDestinationViewModel>(object parameter)
{
var navParameter = string.Empty;
if (parameter != null)
{
navParameter = "?param=" + JsonConvert.SerializeObject(parameter);
}
if (ViewModelRouting.ContainsKey(typeof(TDestinationViewModel)))
{
var page = ViewModelRouting[typeof(TDestinationViewModel)];
this.RootFrame.Navigate(new Uri("/" + page + navParameter, UriKind.Relative));
}
}
}
string
.4. Others Details
With this, I need to register the view model and the NavigationService
interface and implementation, in ViewModelLocator
:
/// <summary>
/// This class contains static references to all the view models in the
/// application and provides an entry point for the bindings.
/// </summary>
public class ViewModelLocator
{
/// <summary>
/// Initializes a new instance of the ViewModelLocator class.
/// </summary>
public ViewModelLocator()
{
ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
if (!SimpleIoc.Default.IsRegistered<IServiceManager>())
{
// For use the fake data do:
// FakeServiceManager.FakeImagePath = "ms-appx:///Images/FakeImage.png";
// SimpleIoc.Default.Register<IServiceManager, FakeServiceManager>();
SimpleIoc.Default.Register<IServiceManager, ServiceManager>();
SimpleIoc.Default.Register<INavigationService, NavigationService>();
}
SimpleIoc.Default.Register<TitlesViewModel>();
SimpleIoc.Default.Register<TitleDetailsViewModel>();
}
/// <summary>
/// Gets the titles view model.
/// </summary>
public TitlesViewModel TitlesViewModel
{
get
{
return ServiceLocator.Current.GetInstance<TitlesViewModel>();
}
}
/// <summary>
/// Gets the title details view model.
/// </summary>
/// <value>
/// The title details view model.
/// </value>
public TitleDetailsViewModel TitleDetailsViewModel
{
get
{
return ServiceLocator.Current.GetInstance<TitleDetailsViewModel>();
}
}
/// <summary>
/// The cleanup.
/// </summary>
public static void Cleanup()
{
// TODO Clear the ViewModels
}
}
and the TitlesViewModel
will be updated with an new method:
/// <summary>
/// The show title details.
/// </summary>
/// <param name="myTitle">
/// The my title.
/// </param>
/// <returns>
/// The <see cref="bool"/>.
/// </returns>
public bool ShowTitleDetails(MyTitle myTitle)
{
if (_navigationService != null)
{
_navigationService.Navigate<TitleDetailsViewModel>(myTitle);
return true;
}
return false;
}
and in TitlesPage.xaml.cs, we will add the:
/// <summary>
/// Handles the OnItemClick event of the Title control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The
/// <see cref="ItemClickEventArgs" /> instance containing the event data.</param>
private void Title_OnItemClick(object sender, ItemClickEventArgs e)
{
var titlesViewModel = DataContext as TitlesViewModel;
if (titlesViewModel != null)
{
var item = e.ClickedItem as MyTitleItemView;
if (item != null)
{
titlesViewModel.ShowTitleDetails(item.Item);
}
}
}
that allows to navigate to the next page. Here, I am using the method from view model to keep the same code between platforms.
Note: The reason for this is because there are differences between Behaviors between platforms, and the implementation I tested for Windows Store apps don't like it.
Source Code Files
- IServiceManager.cs has the
IServiceManager
interface and defines the interface for theServiceManager
. - ServiceManager.cs has the
ServiceManager
class and it encapsulates theNetFlixService
and exposes only the methods that are need inViewModel
. - FakeServiceManager.cs is the implementation of the
IServiceManager
, but is a fake data. - TitlesViewModel.cs has
TitlesViewModel
class and it is used for binding with theDataContext
fromTitlesPage
. - TitleDetailsViewModel that represent the view model that will be binding to the
TitleDetailsPage
. - ViewModelLocator.cs has the
ViewModelLocator
class that helps to binding the view model with the view. - ViewModelHelper.cs has the
ViewModelHelper
class that helps to create grouped data. - TitlesPage.xaml and TitlesPage.xaml.cs that is the main page.
- TitleDetailsPage.xaml that represents the page with details from selected item in TitlesPage.xaml.
- Templates.xaml is a resource dictionary that has the
DataTemplate
for the view. - NetFlixItemTemplateSelector.cs has the
NetFlixItemTemplateSelector
that is used for get theItemTemplate
for each item in theGridView
. - TitleDetailsPage.xaml that represents the page with details from selected item in TitlesPage.xaml.
More Information
- Create a Continuous Client Using Portable Class Libraries
- Windows Phone 8 and Windows 8 Cross Platform Development
- Portable Class Library – Articles and Sample References
- Portable Class Libraries – .NET Framework 4.0
- Portable Class Libraries – .NET Framework 4.5
- Sharing Code in .NET using Portable Class Library
Run the Sample
This sample requires a Nuget package restore. For it, you should follow the steps:
Open the solution (.sln file), the aspect should be:
Go to Top Menu > Tools > Library Package Manager
We will see something like this:
Download process will start...
At the end, is recommend to close the solution and then open again.
To debug the app and then run it, press F5 or use Debug > Start Debugging. To run the app without debugging, press Ctrl+F5 or use Debug > Start Without Debugging.
More Information
Ask me on twitter @saramgsilva.