65.9K
CodeProject 正在变化。 阅读更多。
Home

适用于 UWP 应用的导航系统

starIconstarIconstarIconstarIconstarIcon

5.00/5 (5投票s)

2015年12月20日

CPOL

2分钟阅读

viewsIcon

17626

downloadIcon

290

本技巧旨在为您的 UWP 应用提供一个简单的页面到页面导航系统解决方案。

引言

本技巧旨在为您的 UWP 应用提供一个简单的页面到页面导航系统解决方案。这绝不是最佳解决方案,但对于 90% 的场景来说,这是一个有效的解决方案。它甚至可以自动执行导航,而无需在各处挂接事件处理程序。

背景

  1. 您需要对堆栈数据结构及其功能有一定的了解。
  2. 您必须至少具备任何 Windows 开发平台的最低限度的经验。
  3. 您必须有学习的渴望。
  4. 单例模式(因为我们将探索一种全新的单例实现方式)。
  5. 静态类和静态字段。

静态关键字。

类的一个静态字段可以在任何地方全局访问。

在下面的示例中,b 可以在无需创建对象的情况下访问,而对于 k 才能被访问,则应创建 animal 类的对象,然后才能访问。

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

新的单例模式

此模式允许用户实例化指定类的对象,但在整个应用程序中仅实例化一次。

这是由于 static 关键字所致。

这里 Instance 被标记为 static,因此在所有将通过构造函数实例化的 Navigationservice 之间共享。因此,允许我们检查实例是否为 null,如果不是,则表示已经创建了一个对象,并且不能创建两次。

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;
		}

主要文章 - NavigationService

NavigationService 类使用堆栈来保存要导航回的页面。

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
	}

在这段代码中,让我们看一下 NavigateTo() 方法。

  1. 首先查看堆栈中是否有任何内容。
  2. 如果有,请检查第一个页面是否等于我们要导航到的页面,如果相等,则无需导航到任何地方。
  3. 否则,我们将简单地将页面推入堆栈,然后尝试导航到该页面。
  4. 更新 UWP 应用中的 AppBackButton 的可见性。

现在,我们需要在 App 中实例化它,以便它可以在该项目的类中全局访问。

public static NavigationService NavService { get; protected set; }

rootFrame 以这种方式挂接。

NavService = new NavigationService(ref rootFrame);

传递 ref 是因为我们想要原始对象本身,而不是它的副本。

在页面中使用此服务

<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>

后台代码只是一个 switch 语句,用于从一个页面导航到另一个页面。

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;
			}
		}

项目提供的最终结果应用

希望大家玩得开心!

© . All rights reserved.