﻿# WP7 修練 DAY 02：如何在頁面顯示前自動轉向到其他頁面

我們在設計一些需要登入才能使用的功能時，若使用者進入了會員才能使用的頁面，就會在頁面顯示之前自動導向到另一個頁面，這樣的需求用 ASP.NET 來實作是非常容易的，只要在頁面的 Render 方法執行之前來執行 [Response.Redirect 方法](http://msdn.microsoft.com/zh-tw/library/a8wa7sdt.aspx)就可以了，非常直覺。但是開發環境切換到 WP7 後才發現，要實作這個功能原來沒那麼簡單，你必須花點心思才能做到這樣的需求。

在本次修練開始之前，我們除了預設的 MainPage 頁面外，也另外新增了一個 Login 頁面，如下圖示：

![](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/3cc8d60c1bb4851ca8bc-image_1203.png)

MainPage.xaml 頁面長這樣

![](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/3e9169fa34646df478ca-image_1204.png)

Login.xaml 頁面長這樣

![](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/dd92c4a18e1a7cd89f38-image_1205.png)

因為我們的需求是要求使用者第一次使用 App 時就先登入，所以我們必須在 MainPage 顯示之前就要強迫使用者導向到 Login 頁面。從我上一篇修練文章中可以看到我曾經用過 NavigationService 來實作轉向功能，如果你將轉向的程式寫在 Loaded 事件裡 (如下程式碼)，那麼使用者還是會先看到 MainPage 的完整頁面內容，然後才轉向到 Login 頁面，雖然顯示的時間非常短暫，只有 100 ~ 200ms 而已，但使用者體驗還是非常差，我們必須在頁面顯示前就轉向到其他頁面才行！

```csharp
public MainPage()
{
    InitializeComponent();

    this.Loaded += new System.Windows.RoutedEventHandler(MainPage_Loaded);
}

void MainPage_Loaded(object sender, System.Windows.RoutedEventArgs e)
{
    NavigationService.Navigate(new Uri("/Login.xaml", UriKind.Relative));
}
```

接著你一定會想說把程式碼搬進 MainPage建構子不就好了？很抱歉！在 MainPage 建構子執行的這個時間點，NavigationService 是無法使用的，如果你硬要這麼做，就會出現以下錯誤：

![](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/b29e1b2cc47b04939ab8-image_1206.png)

我研究了一段時間後，其結論就是，這類「頁面顯示前就要轉向」的需求不能在「頁面層級」實現，必須到「應用程式」層級的地方來實現「顯示前轉向」需求，也就是在 App.xaml 與 App.xaml.cs 這個檔案裡撰寫一些程式碼。

如果你曾經研究過 Silverlight 的 [Navigation 框架](http://msdn.microsoft.com/en-us/library/cc838245.aspx)，有可能會知道有個 UriMapper 類別，可以用來做一些網址的路由對應，要在 WP7 裡實現這樣的功能，請參考以下設定步驟：

1\. 首先，我們先開起 App.xaml 檔案，並先新增一個 UriMapper 命名空間

```csharp
xmlns:UriMapper="clr-namespace:System.Windows.Navigation;assembly=Microsoft.Phone"
```

如下圖示：

[![](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/86fbfc82aafc9d78fabc-image_thumb_74.png)](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/f77356c9379fc2cff52d-image_1207.png)

2\. 在應用程式資源的區段 ( <Application.Resources> ) 加入一個 UriMapper 的定義，並且命名為 **LoginPageMapper**，而在其中唯一的一筆 UriMapper 定義裡有兩個屬性需要設定，一個 Uri 是屬性，用來定義比對的網址；另一個是 MappedUri 屬性，用來定義當網址比對成功後應該轉向到哪個網址。

```xml
<UriMapper:UriMapper x:Name="LoginPageMapper">
    <UriMapper:UriMapping Uri="/MainPage.xaml"
                          MappedUri="/Login.xaml" />
</UriMapper:UriMapper>
```

![](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/1800d74f7067456dd87b-image_1208.png)

3\. 雖然已經定義了一筆 UriMapper 定義，並不代表 UriMapper 的規則已經正式啟用，這裡我們所建立的只是一個「應用程式資源」而已，所以還必須開啟 App.xaml.cs 並在 **App()** 建構子最後加上以下程式：

```csharp
RootFrame.UriMapper = Resources["LoginPageMapper"] as UriMapper;
```

此時我們的 UriMapper 就正式生效了，如果你按下 F5 執行，就會發現首頁 ( MainPage.xaml ) 事實上並沒有被導向，而是網址被改寫 (Rewrite) 成 **/Login.xaml** 了，但我們看起來卻好像是被導向的感覺！

接下來就是如何靈活運用 UriMapper 的時刻，你可以在 **App()** 建構子透過程式碼動態修改 MappedUri 位址，好讓頁面能夠轉向 ( 雖然是改寫網址，但我還是寫轉向比較容易理解 ) 到其他頁面。

例如說以下程式碼，我可以讀取在隔離儲存區的應用程式設定中是否已經設定過 Username 這個鍵值，如果有的話我就視為此人已經登入過，並動態的把 MappedUri 屬性修改成 **/MainPage.xaml** 這個位址：

```csharp
var mapper = Resources["LoginPageMapper"] as UriMapper;

if (IsolatedStorageSettings.ApplicationSettings.Contains("Username"))
{
    mapper.UriMappings[0].MappedUri = new Uri("/MainPage.xaml", UriKind.Relative);
}

RootFrame.UriMapper = mapper;
```

請注意：若要使用 IsolatedStorageSettings 類別必須引用 System.IO.IsolatedStorage 命名空間才行喔!

```csharp
using System.IO.IsolatedStorage;
```

當然，你也可以定義多筆 UriMapper 定義，來宣告其他頁面的網址對應規則，或撰寫更複雜的判斷規則，如此一來整個 WP7 App 的各種頁面顯示前轉向的功能與判斷邏輯就可以集中管理，也不失為一種好方法。

**今日修練總結**

原來在 WP7 的開發模式裡，要實作出「頁面顯示前就轉向」也有這麼些學問，果然跟我們一般在做網頁開發時差異頗大。透過 UriMapper 的操作技巧著實非常方便，如能更深入研究 Silverlight 的巡覽框架 (Navigation Framework)相信還能有其他的體悟。

**相關連結**

-   [Redirecting an initial navigation](https://learn.microsoft.com/en-us/archive/blogs/ptorr/redirecting-an-initial-navigation)
-   [Introducing the concept of “Places”](https://web.archive.org/web/20100831014443/http://blogs.msdn.com:80/b/ptorr/archive/2010/08/28/introducing-the-concept-of-places.aspx)
-   [How to change the startup page of a WP7 Application](http://stackoverflow.com/questions/4441872/how-to-change-the-startup-page-of-a-wp7-application)
-   [Navigation Overview – Silverlight](http://msdn.microsoft.com/en-us/library/cc838245.aspx)  /  [巡覽概觀 – Silverlight](http://msdn.microsoft.com/zh-tw/library/cc838245.aspx)
-   [Execution Model Overview for Windows Phone](http://msdn.microsoft.com/en-us/library/ff817008.aspx)
