Windows Phone 7 – Navigation Framework原理概論
在學習Windows Phone 7開發時,如果你本身對Silverlight或WPF實作有些了解的話,Navigation Framework我相信一定是大家
會用到的部分。因此,這一篇是我自己在研讀Windows Phone 7 Application開發時,我覺得需要花一些時間去好好搞懂運作
原理的部分。
首先,Windows Phone 7的Application主要是基於Silverlight Page Model,提供用戶可以導向指定的Page,更換不同的內容,
因此,你可以建立很多個頁面(Page)在同一個框架(Frame)內進行瀏覽。那在Frame與Page二個的運作關係,往下就仔細說明。
〉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裡,也許你會發現這一段程式碼:
1: // Do not add any additional code to this method
2: private void CompleteInitializePhoneApplication(object sender, NavigationEventArgs e)
3: {
4: // Set the root visual to allow the application to render
5: if (RootVisual != RootFrame)
6: RootVisual = RootFrame;
7:
8: // Remove this handler since it is no longer needed
9: RootFrame.Navigated -= CompleteInitializePhoneApplication;
10: }
不知道你是否跟我一樣好奇,什麼是RootVisual。
其實在整個運作Application一開始,還沒有真正載入Page或Frame的時候(也就是在程式出現splash screen的時間點),該Application是
沒有主畫面的,因此,可以看到當App.xaml在InitializePhoneApplication()方法時,寫上了下面程式碼:
1: // Do not add any additional code to this method
2: private void InitializePhoneApplication()
3: {
4: if (phoneApplicationInitialized)
5: return;
6:
7: // Create the frame but don't set it as RootVisual yet; this allows the splash
8: // screen to remain active until the application is ready to render.
9: RootFrame = new PhoneApplicationFrame();
10: RootFrame.Navigated += CompleteInitializePhoneApplication;
11:
12: // Handle navigation failures
13: RootFrame.NavigationFailed += RootFrame_NavigationFailed;
14:
15: // Ensure we don't initialize again
16: phoneApplicationInitialized = true;
17: }
在程式一開始初始化了一組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來保留目前狀態或識
別導向來往二邊的狀態與資訊,進一步控制呈現的資訊內容。
References:
‧WP7 Navigation in depth | Navigation Framework & Frame and Page Navigation Overview for Windows Phone (必讀)
‧How to: Perform Page Navigation on Windows Phone & Exercise 1: Introduction to Navigation in Windows Phone
‧WP7 Developer Blog : 解决WP7应用中循坏导航的问题 & Solving Circular Navigation in Windows Phone Silverlight Applications
‧Exit from Silverlight WP7 Application & How to Quit a WP7 Silverlight Application
‧.NET Framework 4 - NavigationService 類別
‧Silverlight for windows phone 7 Application life cycle & Navigation
‧Removing a page from the navigation stack
‧Windows Phone 7 Quick Tip #3 – Use a NavDictionary to pass state between pages (必讀)
‧WP7 Development Tip of the Day: Navigating between pages: NavigateUri vs. NavigationService (必讀)
‧Redirecting an initial navigation
‧Introducing the concept of “Places”