在学习Windows Phone 7开发时,如果你本身对Silverlight或WPF开发有些了解的话,Navigation Framework我相信一定是大家
会用到的部分。因此,这一篇是我自己在学习Windows Phone 7 Application开发时,我觉得需要花一些时间去好好搞懂他底层
原理的部分。
首先,Windows Phone 7的Application主要是基于Silverlight Page Model,提供用户可以导向指定的Page,更换不同的内容,
因此,你可以建立很多个页面(Page)在同一个框架(Frame)内进行浏览。那在Frame与Page二个的运作关系,往下就仔细说明。
在这里我不得不感谢一直支持我的卤面网版主,是他让我提起兴趣写了这么一篇文章,再次感谢卤面网,一个非常不错的wp7开发论坛,后面我也将再次向大家发布几篇高质量文章,请大家到卤面上找我吧,呵呵
进入正题:
〉PhoneApplicationFrame与PhoneApplicationPage:
通过过下图可以了解二者之间的关系,它们都是Microsoft.Phone.Controls Namespace里重要的组件:
(a) PhoneApplicationFrame ( PhoneApplicationFrame Class ):
一个WP7 Application会有一个Frame,该Frame专门来控制内部包括的Page、Control与其他的Element。
负责控制整个WP Application呈现的方式,例如:Orientation Property、Render的范围等,更包括Status Bar与ApplicationBar。
以上是MSDN上的说明,PhoneApplicationFrame可以用的功能还包括:
a-1. PhoneApplicationPage之间的资料交换;
a-2. 结合App.xaml控制整个ApplicationPage内的内容与控件
a-3. 控制PhoneApplicationPage的切换
有几个Events要特别注意:Navigated、Navigating、NavigationFailed与NavigationStopped,这四个是在进行Navigate过程时,
当ApplicationPage里提出Navigate()、GoBack()或GoForward()后,会将控制权移转至Frame透过四个Event来进行处理。
(b) PhoneApplicationPage ( PhoneApplicationPage Class ):
它是个Page类,Page类提供运行Navigation Framework的处理事件与服务。因此,在一些Sample Code看到的Navigate(),
其实都是通过Page类进行运作,往上抛转给PhoneApplicationFrame来进行导向的任务。PhoneApplicationPage会在产生一份
Xaml文件时,就被给予一个对应,它内容可以包括所有User Control里的资料,当然也有:pivot、chart等。另外,针对Orientation
的改变,即透过OrientationChanged该Event来负责。如果你的代码里针对方向有特别需要,该Event将会协助你处理不少事情。
上面叙述了关于整个Windows Phone Application运行的基本元素,接下来说明元素之间如何互相导向与移动,这是在实例
过程里,我觉得需要来了解的:
〉Page导航的重要元素– Navigation Framework:
Windows Phone Applications是由Silverlight Pages所组合而成,为了让Pages之间可以互相浏览与串联,因此,存在了一个
「Navigation Stack」。该Stack透过First in first out的概念储存了所有浏览过程的Page,协助按下Back键时回到目标的页面。
但在此,MSDN上也提到「过度使用Page,将可能造成Application储存了多余残留的Page资讯在navigation stack中,影响应
用程度的性能与可靠性」。
针对Page类处理导航任务,可以透过NavigationService.Navigate()、GoBack()或GoForward()来进行,然而这三个方法对于
Page的影响与运作流程,可以分成五个必要的Event Handler:
〉Loaded (代表每一次页面载入完成后,触发的事件。)
〉Unloaded (从目前该页面要导向另一个页面时,触发的事件。)
〉OnNavigatingFrom (通过NavigationService,要从目前页面离开过程时,触发该事件。)
〉OnNavigatedFrom (通过NavigationService,要从目前页面离开后,触发该事件。)
OnNavigatingFrom与OnNavigatedFrom二个是先后顺序的关系,通常处理事件都会在OnNavigatedFrom里,这不代表
你就不能加入在OnNavigatingFrom处理需要任务,只是OnNavigatingFrom故名思义,它是被触发于当目前页面不被在
使用之前,此时,我们可以用于完成一些任务,例如:关闭目前正在播放的动画等。
〉OnNavigatedTo (透过NavigationService,前往新的页面时会自动触发新的页面的OnNavigatedTo事件。)
每一个XAML文件针对Page载入触发顺序,可以通过下图来加以说明:
(a) 从MainPage.xaml要前往SecondPage.xaml时,先触发了本身的OnNavgatingFrom与OnNavigatedFrom准备结束本页;
(b) 接着SecondPage.xaml触发OnNavigationTo事件,准备把本页要用的资料透过上一页转过来;
(c) MainPage.xaml完成NavigateService导向SecondPage.xaml后,触发Unloaded事件;
(d) 最后SecondPage.xaml触发Loaded事件开始载入该页面需要组件与内容;
至于二页资料要传过去的方法,可以参考该篇的介绍方法:< How to: Perform Page Navigation on Windows Phone >,
它透过NavigateService.Navigate()来传递参数在URL中,并且配合新的一页的OnNavigatedTo()来处理取得的资料。
上面运作的顺序,将会影响在处理Page交换时,资料的换手与储存。
当然,你也可以直接把页面之间要共享的资料内容,变成如下图的作法:
透过由App.xaml集中控管Page之间交换的信息,这样有一个好处:只要透过App.xaml负责处理Application进入
deActive与Actived时要储存与取得信息的任务。不需要每一个Page都去负责处理Tombstoning造成的影响。
另外,在使用Navigate时,我在其他文件里有看Sample会去对NavigateContext做一些处理与说明,那最后就来看看它是什么:
〉Page.NavigationContext:
专门处理Navigation请求的内容,上述提及的透过Url传送参数的方法,就是把要传递的内容放置于该NavigationContext类别中。
透过QueryString属性来取得参数值。
====
以上是介绍WP7运作配合Navigation Framework的运用,这一篇其实蛮多基本的原理,撰写出来是为了让自己能够
更清楚他们运作原理的规则,才不会一直在开发上遇到一些根本的问题,而花费不少时间去走冤枉路。
学习WP7程式也有些时日,其实在整个开发过程里,遇到蛮多原理性的问题。由于我本身对Silverlight原理没有太深固的基础,
因此,很常会遇到不太明白为何画面没有办法正常出现或是导向失败,甚至连要如何透过Back离开自己开发的App也不明白。
这样的开发经验,其实让我感触深刻,特别将在学习整个Silverlight与WP7上学习的心得,通过该篇文章撰写一些必懂的一些概念。
[ 补充 ]
〉WP7换页时的作法比较– PhoneApplicationPage.Content与PhoneApplicationPage.NavigationService:
(a)使用Content来进行换页,其实原有的Page仍然存在,只是内容被转换成了新的一个画面,这样原先存在
Page中的内容,将会被覆盖掉。按下Back键时,其画面不会回到上一个,而一直存在相同的页面。
(b)使用NavigationService来换页,实际上是将Frame目前控件的Page指定另一个新的Page,原有的Page内容也会被
保留下来。按下Back键时,就可以回到上一个Page。注意的是,Back键回去的Page是刚才被产生的instance,
它并不是一个全新的Page。
〉PhoneApplicationFrame与RootVisual:
打开App.xaml.cs里,也许你会发现这一段代码:
// Do not add any additional code to this method
private void CompleteInitializePhoneApplication( object sender, NavigationEventArgs e)
{
// Set the root visual to allow the application to render
if (RootVisual != RootFrame)
RootVisual = RootFrame;
// Remove this handler since it is no longer needed
RootFrame.Navigated -= CompleteInitializePhoneApplication;
}
不知道你是否跟我一样好奇,什么是RootVisual。
其实在整个运作Application一开始,还没有真正载入Page或Frame的时候(也就是在程式出现splash screen的时间点),该Application是
没有主画面的,因此,可以看到当App.xaml在InitializePhoneApplication()方法时,写上了下面代码:
// Do not add any additional code to this method
private void InitializePhoneApplication()
{
if (phoneApplicationInitialized)
return ;
// Create the frame but don't set it as RootVisual yet; this allows the splash
// screen to remain active until the application is ready to render.
RootFrame = new PhoneApplicationFrame();
RootFrame.Navigated += CompleteInitializePhoneApplication;
// Handle navigation failures
RootFrame.NavigationFailed += RootFrame_NavigationFailed;
// Ensure we don't initialize again
phoneApplicationInitialized = true ;
}
在代码一开始初始化了一组RootFrame(也就是PhoneApplicationFrame),并且在RootFrame完成Navigated事件处理时,即调用
CompleteInitializePhoneApplication()事件处理者,该事件处理者就把RootFrame指定给RootVisual,让应用程序得知主画面是谁。
然而,Frame成为了主画面,而PhoneApplicationPage只是Frame中的Content。
换句话说,RootVisual就是用来取得或设定主要应用程序的UI。所以我们才可以透过Frame来控制所有的Page。但是,
它有一个先天的条件:「您只能从代码码设定RootVisual属性值一次,但是可不限次数地取得其值。」这点要特别注意。
〉离开WP7程序:
虽然说这个标题不是什么太新鲜的话题了,但想大家都知道要从自己程序离开的话,直接透过丢出一个Exception来进行处理,
就可以离开自己的程式了,但也还有其他的方式。那就是透过「Microsoft.XNA.Game」这个Namespace,直接使用Game类别提供
的”Exit()”方法来离开。大家可以试看看。
〉Application Page Model of Windows Phone:
Application Page Model是WP7整个运作的关键,它与该篇介绍的Navigation Framework是互相关联的,因此,如果这篇内容,
有写的不够详细的地方,可以直接往Application Page Model这个关键字下去搜寻。另外,顺带一提,在MSDN文件里有看到
Page与Screen的定义,二者的差别在于:
Page | Screen | |
A user-recognizable collection of persistent state. | not a user-recognizable collection of persistent state | |
as a Silverlight page that contains information, memorable content, or links to other pages. | such as a pop-up window, dialog box, or splash screen . |
〉选取MSDN上针对Navigation使用的建议:
A. Screens and Non-Navigational Transitions
针对transient UI(短暂出现的UI),建议使用Pop-Up Control去呈现内容。学习BackKeyPress事件去隐藏PopUp(或Dialog box)的内容。
B. Multiple Content Views
对于使用多个页面显示内容,建议可以使用多个DataContext元件来通过与用户的操作进行信息的互动与呈现。当然,你可以使用
多个Page来使用会比较容易,但必须注意Back键的处理以免造成多余的stack信息被储存下来。
C. Saving State and Tombstoning
建议注意代码储存目前状态的处理,由于程序可能被转换成tombstone,因此,可以透过NavigationContext API来保留目前状态或识
别导向来往二边的状态与信息,进一步控制呈现的信息内容。
我希望你能喜欢我的文章!如果你有更多想法,请到卤面网 wp7开发论坛(codewp7.com)问答区联系我,我会很高兴知道你在想什么。同时wp7交流QQ群172765887中,也能找到我的身影,感谢大家,也欢迎大家关注我的微薄(www.weibo.com/codewp7)