适用于 UWP 应用的导航系统





5.00/5 (5投票s)
本技巧旨在为您的 UWP 应用提供一个简单的页面到页面导航系统解决方案。
引言
本技巧旨在为您的 UWP 应用提供一个简单的页面到页面导航系统解决方案。这绝不是最佳解决方案,但对于 90% 的场景来说,这是一个有效的解决方案。它甚至可以自动执行导航,而无需在各处挂接事件处理程序。
背景
- 您需要对堆栈数据结构及其功能有一定的了解。
- 您必须至少具备任何 Windows 开发平台的最低限度的经验。
- 您必须有学习的渴望。
- 单例模式(因为我们将探索一种全新的单例实现方式)。
- 静态类和静态字段。
静态关键字。
类的一个静态字段可以在任何地方全局访问。
在下面的示例中,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()
方法。
- 首先查看堆栈中是否有任何内容。
- 如果有,请检查第一个页面是否等于我们要导航到的页面,如果相等,则无需导航到任何地方。
- 否则,我们将简单地将页面推入堆栈,然后尝试导航到该页面。
- 更新 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=""
FontSize="20"
Style="{StaticResource TabStyleWithGlyph}"
Checked="RadioButton_Checked"/>
<RadioButton GroupName="Tabs"
Content="Timer"
Tag=""
FontSize="20"
Checked="RadioButton_Checked"
Style="{StaticResource TabStyleWithGlyph}" />
<RadioButton GroupName="Tabs"
Content="StopWatch"
Tag=""
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;
}
}
项目提供的最终结果应用