WP7 - 動態轉換初始的Default Page

Windows Phone 7 - 動態轉換初始的Default Page

開發Windows Phone 7的App也好,iPhone或Android的程式也好,它們都有一份用於描述App基本設定或參數的文件,

以WP7為例:「WMAppManifest.xml」。這一份檔案是每個WP7 Project自動產生,如下描述內容:

   1: <?xml version="1.0" encoding="utf-8"?>
   2:  
   3: <Deployment xmlns="http://schemas.microsoft.com/windowsphone/2009/deployment" AppPlatformVersion="7.0">
   4:   <App xmlns="" ProductID="{8158919a-d617-424c-af45-b20370f3ea5f}" Title="AdvTest" RuntimeType="Silverlight" 
   5:        Version="1.0.0.0" Genre="apps.normal"  Author="AdvTest author"
   6:        Description="Sample description" Publisher="AdvTest">
   7:     <IconPath IsRelative="true" IsResource="false">ApplicationIcon.png</IconPath>
   8:     <Capabilities>
   9:       <Capability Name="ID_CAP_GAMERSERVICES"/>
  10:       <Capability Name="ID_CAP_IDENTITY_DEVICE"/>
  11:       <Capability Name="ID_CAP_IDENTITY_USER"/>
  12:       <Capability Name="ID_CAP_LOCATION"/>
  13:       <Capability Name="ID_CAP_MEDIALIB"/>
  14:       <Capability Name="ID_CAP_MICROPHONE"/>
  15:       <Capability Name="ID_CAP_NETWORKING"/>
  16:       <Capability Name="ID_CAP_PHONEDIALER"/>
  17:       <Capability Name="ID_CAP_PUSH_NOTIFICATION"/>
  18:       <Capability Name="ID_CAP_SENSORS"/>
  19:       <Capability Name="ID_CAP_WEBBROWSERCOMPONENT"/>
  20:     </Capabilities>
  21:     <Tasks>
  22:       <DefaultTask  Name ="_default" NavigationPage="MainPage.xaml"/>
  23:     </Tasks>
  24:     <Tokens>
  25:       <PrimaryToken TokenID="AdvTestToken" TaskName="_default">
  26:         <TemplateType5>
  27:           <BackgroundImageURI IsRelative="true" IsResource="false">Background.png</BackgroundImageURI>
  28:           <Count>0</Count>
  29:           <Title>AdvTest</Title>
  30:         </TemplateType5>
  31:       </PrimaryToken>
  32:     </Tokens>
  33:   </App>
  34: </Deployment>

該文件代表整個Silverlight或XNA的WP7 App的主要描述檔,其內容包括:Product IDs、版本資訊、執行環境、資源檔位置等,

並且這份文件會隨著每次建置專案時,更新其中的內容。然而,這份文件的主要目的在於:

(1) 當作App上傳至Marketplace的使用資訊(類似:App的身份證):用於識別該App支援的硬體、環境與資源;

(2) Marketplace根據此文件將上傳的App歸納至對應的Application database之中;

 

以下詳細說明每段MetaData的定義:

WMAppManifest

(1) Deployment: < Deployment ></ Deployment >

    此範例主要定義XML的Namespace與AppPlatformVersion的資訊。

(2) Application: <App></App>

    此標籤中的屬性是真正描述該App的重要資訊,包括:App ID、Title、Runtime Type等;詳細的內容,可以參考上述的連結;

但在Application標籤中,有幾個要特別注意的,以下我將列舉出來:

a. Capabilities: <Capabilities></Capabilities>

    此標籤的定義在描述App支援的主要標籤,它與Application標籤中屬性描述的部分比較不相同,它強調在於使用WP7本身於硬

體資訊的取得,因此,通常除非開發的App有特別需要調整針對硬體資訊取得之外,Capabilities裡的內容,比較不會去動到它,

以下簡介從MSDN擷取出來的內容:

Capability ID/Name (Type: String)

Description

ID_CAP_NETWORKING 描述該App會使用到網路連線的能力,如果App需用到網路即一定要加上,用於向使用者宣告此App將會需要網路連線可能會需要用戶付擔漫遊與網路費用。
ID_CAP_IDENTITY_DEVICE 描述該App使用特定的設備訊息,例如:device ID、製造商名稱…等。
ID_CAP_IDENTITY_USER 描述App使用anonymous LiveID (匿名LiveID)識別用戶。這個通常不太會去在意,因為除非你的App需要結合Live ID這個可能會影響,例如:登入MSN、打卡等。
ID_CAP_LOCATION 描述App可與Location Service結合。
ID_CAP_SENSORS 描述App可使用Windows Phone sensors。
ID_CAP_MICROPHONE 描述App可使用麥克風。加了這個標籤,代表App可以在沒有視覺畫面呈現下,使用麥克風來記錄所述說的內容。
ID_CAP_MEDIALIB 描述App可以連結Media Library。
ID_CAP_GAMERSERVICES 描述App將與XBOX Live APIs進行連結。這需要被宣告出來,因為代表App將會與XBOX共享資料內容。
ID_CAP_PHONEDIALER 描述App可與電話功能結合,也支援在沒有視覺畫面呈現下繼續使用。
ID_CAP_PUSH_NOTIFICATION 描述App可以支援Push Notification Service的使用,這需要被宣告出來,讓用戶知道該App可能會造成他們需要付擔網路費用。
ID_CAP_WEBBROWSERCOMPONENT 描述App可以使用Web Browser元件,也代表Web Browser使用時需要注意有安全性影響的Script。

b. Tasks標籤

    該標籤定義了每一個App啟動時,預設第一個啟動的Page,不過這只支援於Silverlight App,XNA的App除外,主要二個屬性:

Attribute Description
Name Type: String. The default name is “_default.”
NavigationPage Type: String. This is the navigation page that a task will navigate to in the application when it starts.

c. Tokens標籤

    該標籤主要是針對標示在Start Page中的Tile的呈現,比較接近Push Notification Service比較會使用到。例如:

Count、Title與BackgroundImageURI這些都是定義Tile呈現需要的東西。

 

了解了WMAppMainfest.xml之後,接下來是本篇的重點,「如何動態調整App的初始頁面?

這個問題不知道大家沒有跟我一樣遇到過,舉個例子來說:「像公車動態查詢提供用戶可以先設定當用的縣市,這樣就不需每次登入

都先從第一頁開始選要去的縣市再來選公車。」理解了這個情境之後,接下來提供程式與圖示來加以說明:

〉實作流程架構

000

當App啟動時主要載入第一個要啟動的畫面流程,如上圖所示,其中有一個關鍵的事件:「RootFrame.Navigate(“/MainPage.xaml”)」。

如果熟悉整個WP7 App在Page運作的原理<Windows Phone 7 – Navigation Framework原理概論>,應該很清楚知道,一個App只有一個Frame,

從App.xaml.cs裡進去,就可以找到它PhoneApplicationFrame,那就是RootFrame了。RootFrame管理整個App中所有Page運作的方式,

因此,如果要達到動態修改預設載入的第一個Page,那勢必要對RootFrame下手了。

 

〉範例程式

(1) 先為RootFrame增加一個Navigating的事件處理,為了是擷取每一次RootFrame進行Page導航時的事件補捉;

   1: //在App.xaml.cs中的建構子,為RootFrame增加Navigating的事件處理;
   2: public App()
   3: {
   4:     ....
   5:     // Standard Silverlight initialization
   6:     InitializeComponent();
   7:  
   8:     // Phone-specific initialization
   9:     InitializePhoneApplication();
  10:  
  11:     //增加RootFrame針對Navigating的事件處理;
  12:     RootFrame.Navigating += new NavigatingCancelEventHandler(RootFrame_Navigating);
  13: }

(2) 針對RootFrame_Navigating提供事件處理的邏輯內容;

   1: void RootFrame_Navigating(object sender, NavigatingCancelEventArgs e)
   2: {
   3:     //識別目前RootFrame要前往的頁面是否為MainPage.xaml
   4:     if (e.Uri.ToString().Contains("/MainPage.xaml") != true)
   5:     {
   6:         //不是,讓RootFrame繼續完成自己的任務
   7:         return;
   8:     }
   9:     //是,代表要轉換RootFrame指定的頁面到我們要的頁面
  10:     //先取消原本RootFrame要導航的動作
  11:     e.Cancel = true;
  12:     //再透過Delegate移動要去的指定頁面
  13:     RootFrame.Dispatcher.BeginInvoke(delegate
  14:     {
  15:         RootFrame.Navigate(new Uri("/Second.xaml", UriKind.Relative));
  16:     });
  17: }

如上的程式碼,就可以讓App啟動時,自動轉到別的頁面去,而不是預設到MainPage.xaml。

001

 

‧重點元素說明

〉NavigatingCancelEventHandler & NavigatingCancelEventArgs

針對Navigating事件的處理方法,提供可以取消事件的功能,透過這個方法,即可以在RootFrame進行Navigating時,

識別要導航的對象,加以進行轉向與取消原有要移動的事件。由於它是一個委派的方法,因此,當要從此事件通知

RootFrame進行新的導航時,需要再透過Dispatcher.BeInvoke來進行畫面的切換

 

〉UriMapper

另外,也可以透過UriMapper類別來達到相同的處理結果。以後擷錄<Redirecting an initial navigation>的程式碼:

   1: void SetupUriMapper()
   2: {
   3:   // Get the UriMapper from the app.xaml resources, and assign it to the root frame
   4:   UriMapper mapper = Resources["mapper"] as UriMapper;
   5:   RootFrame.UriMapper = mapper;
   6:  
   7:   // Our dummy check -- does the current time have an odd or even number of seconds?
   8:   DateTime time = DateTime.Now;
   9:   int seconds = time.Second;
  10:   bool isOdd = (seconds % 2) == 1;
  11:  
  12:   // Update the mapper as appropriate
  13:   if (isOdd)
  14:     mapper.UriMappings[0].MappedUri = new Uri("/odd.xaml?method=UriMapper&time=" + time.ToLongTimeString(), UriKind.Relative);
  15:   else
  16:     mapper.UriMappings[0].MappedUri = new Uri("/even.xaml?method=UriMapper&time=" + time.ToLongTimeString(), UriKind.Relative);
  17: }

UriMapper是透過事先定義好於資源檔(Resources)中的Key/Value值,來進行轉換。

透過UriMapper可以把每一個Uri之間轉換的集合或規則,先定義完成,再藉由Uri的指定來要求RootFrame進行畫面的移動。

 

====

以上是我針對這次NavigateService類別操作時,遇到一個很好玩的情境,把它整理清楚以理解可以實作的範圍。

 

References:

Redirecting an initial navigation (必讀)

How to: Use the Capability Detection Tool for Windows Phone

NavigatingCancelEventHandler 委派

Types of Push Notifications for Windows Phone

UriMapper 類別

System.Windows.Navigation 命名空間