Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

A Navigation System for UWP Apps

0.00/5 (No votes)
20 Dec 2015 1  
This tip is aimed at providing a simple solution for simple page to page navigation system for your UWP apps.

Introduction

This tip is aimed at providing a simple solution for simple page to page navigation system for your UWP apps. This is by no means the best solution but is a valid solution for 90% of the scenarios. This even automates the Navigation without the need to hooking up event handlers everywhere.

Background

  1. You are expected to know a bit about the Stack Datastructure and its functions
  2. You must have at least minimum experience with any Windows development platform
  3. You must have the curiosity to learn
  4. Singleton Pattern (because we are going to explore a whole new way of implementing a Singleton)
  5. Static classes and Static fields

Static-Keyword

A Static field of a Class can be accessed anywhere globally.

In the example below, b is accessible without having to create an object while for k to be accessed, an object of the animal class should be created and then accessed.

public class Animal
	{
		public static int b = 90;
		public int k;
	}
 
	public class Dog
	{
		public Dog()
		{
			var a = Animal.b;
		}
	}

The NEW Singleton Pattern

This pattern allows the user to instantiate an object of the specified class but only once throughout the application.

This is possible due to the static keyword.

Here the Instance is marked static and hence is shared among all the Navigationservice that will be instantiated by using the constructor. Hence allowing us to check if the instance is null and if it isn't, it means one object has already been created and can't be created twice.

public class NavigationService
	{
		public static NavigationService Instance { get; protected set; }
 
		public NavigationService()
		{
			//Check is the instance doesnt already exist.
			if (Instance != null)
			{
				//if there is an instance in the app 
				//already present then simply throw an error.
				throw new Exception
				("Only one navigation service can exist in a App.");
			}
			//setting the instance to the static instance field.
			Instance = this;
		}

The Main Article - NavigationService

The NavigationService class uses the stack to hold the pages to navigateback.

public class NavigationService
	{
		/// <summary>
		/// This holds the instance to the Only NavigationService in this app.
		/// </summary>
		public static NavigationService Instance { get; protected set; }
 
		/// <summary>
		/// This will hold the reference to the frame that is to be manipulated.
		/// </summary>
		private Frame frame;
 
		/// <summary>
		/// The Stack of pages to enable Stack based Navigation.
		/// </summary>
		public Stack<Type> PageStack { get; protected set; }
 
		#region CTOR
		/// <summary>
		/// The default constructor to instantiate this class with reference to a frame
		/// </summary>
		/// <param name="frame">The referenced frame</param>
		public NavigationService( ref Frame frame )
		{
			//Check is the instance doesnt already exist.
			if (Instance != null)
			{
				//if there is an instance in the app already present then simply throw an error.
				throw new Exception("Only one navigation service can exist in a App.");
			}
			//setting the instance to the static instance field.
			Instance = this;
			//setting the frame reference.
			this.frame = frame;
			//initializing the stack.
			this.PageStack = new Stack<Type>();
 
 
			//Hooking up the events for BackRequest both for Big Windows and for Phone.
 
			SystemNavigationManager.GetForCurrentView().BackRequested += 
							NavigationService_BackRequested;
 
			if (ApiInformation.IsTypePresent("Windows.Phone.UI.Input.HardwareButtons"))
			{
				Windows.Phone.UI.Input.HardwareButtons.BackPressed += 
							HardwareButtons_BackPressed; ;
			} 
		} 
 
		#endregion
 
		#region Navigation Methods
 
		public void NavigateTo( Type pageType , object parameter )
		{
			if (PageStack.Count > 0)
			{
				if (PageStack.Peek() == pageType)
					return;
			}
			PageStack.Push(pageType);
			frame.Navigate(pageType , parameter);
			UpdateBackButtonVisibility();
		}
 
		public void NavigateBack()
		{
			if (frame.CanGoBack)
				frame.GoBack();
			PageStack.Pop();
			UpdateBackButtonVisibility();
		}
 
		public void NavigateToHome()
		{
			while (frame.CanGoBack)
				frame.GoBack();
		}
		#endregion
 
 
		#region BackButtonVisibilty Region
		void UpdateBackButtonVisibility()
		{
			SystemNavigationManager.GetForCurrentView().
				AppViewBackButtonVisibility = frame.CanGoBack ?
				 AppViewBackButtonVisibility.Visible : 
				 	AppViewBackButtonVisibility.Collapsed;
		}
		#endregion
 
		#region Event Methods for windows and phone
 
		private void NavigationService_BackRequested
		( object sender , BackRequestedEventArgs e )
		{
			this.NavigateBack();
		}
 
		private void HardwareButtons_BackPressed
		( object sender , Windows.Phone.UI.Input.BackPressedEventArgs e )
		{
			this.NavigateBack();
		}
 
		#endregion
	}

In this code, let's look at the NavigateTo() method.

  1. First see if stack has anything.
  2. If it has, go ahead and check if the first one is equal to the page we are trying to navigate to, if it's equal, then we need not navigate anywhere.
  3. Else, we are going to simply push the page up the stack and then try Navigate to the page.
  4. Update the AppBackButton's Visibility in the UWP app.

Now, we need to instantiate it in the App so that it is globally accessible to all the classes in this project.

public static NavigationService NavService { get; protected set; }

The rootFrame is hooked up in this way.

NavService = new NavigationService(ref rootFrame);

The ref is passed because we want the original object itself but not a copy of it.

Consuming this services in a page:

<StackPanel HorizontalAlignment="Stretch"
						VerticalAlignment="Stretch"
						Orientation="Horizontal">
			<RadioButton GroupName="Tabs"
							 Content="Alarms"
							 Tag="&#xE700;"
							 FontSize="20"
							 Style="{StaticResource TabStyleWithGlyph}"
							 Checked="RadioButton_Checked"/>
			<RadioButton GroupName="Tabs"
							 Content="Timer"
							 Tag="&#xE700;"
							 FontSize="20"
							 Checked="RadioButton_Checked"
							 Style="{StaticResource TabStyleWithGlyph}" />
			<RadioButton GroupName="Tabs"
							 Content="StopWatch"
							 Tag="&#xE700;"
							 FontSize="20"
							 Checked="RadioButton_Checked"
							 Style="{StaticResource TabStyleWithGlyph}" />
		</StackPanel>
		<Frame Grid.Row="1"
				 x:Name="rootFrame"
				 x:FieldModifier="public">
		
		</Frame>

The code behind is just a switch case to navigate from one page to another:

private void RadioButton_Checked( object sender , RoutedEventArgs e )
		{
			switch ((sender as RadioButton).Content.ToString())
			{
				case "Alarms":
					App.NavService.NavigateTo(typeof(Alarms) , null);
					break;
				case "Timer":
					App.NavService.NavigateTo(typeof(TImer) , null);
					break;
				case "StopWatch":
					App.NavService.NavigateTo(typeof(StopWatch) , null);
					break;
				default:
					break;
			}
		}

The end result app as provided by the project:

Hope you guys had fun!

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here