我們在設計一些需要登入才能使用的功能時,若使用者進入了會員才能使用的頁面,就會在頁面顯示之前自動導向到另一個頁面,這樣的需求用 ASP.NET 來實作是非常容易的,只要在頁面的 Render 方法執行之前來執行 Response.Redirect 方法就可以了,非常直覺。但是開發環境切換到 WP7 後才發現,要實作這個功能原來沒那麼簡單,你必須花點心思才能做到這樣的需求。
在本次修練開始之前,我們除了預設的 MainPage 頁面外,也另外新增了一個 Login 頁面,如下圖示:
MainPage.xaml 頁面長這樣
Login.xaml 頁面長這樣
因為我們的需求是要求使用者第一次使用 App 時就先登入,所以我們必須在 MainPage 顯示之前就要強迫使用者導向到 Login 頁面。從我上一篇修練文章中可以看到我曾經用過 NavigationService 來實作轉向功能,如果你將轉向的程式寫在 Loaded 事件裡 (如下程式碼),那麼使用者還是會先看到 MainPage 的完整頁面內容,然後才轉向到 Login 頁面,雖然顯示的時間非常短暫,只有 100 ~ 200ms 而已,但使用者體驗還是非常差,我們必須在頁面顯示前就轉向到其他頁面才行!
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 是無法使用的,如果你硬要這麼做,就會出現以下錯誤:
我研究了一段時間後,其結論就是,這類「頁面顯示前就要轉向」的需求不能在「頁面層級」實現,必須到「應用程式」層級的地方來實現「顯示前轉向」需求,也就是在 App.xaml 與 App.xaml.cs 這個檔案裡撰寫一些程式碼。
如果你曾經研究過 Silverlight 的 Navigation 框架,有可能會知道有個 UriMapper 類別,可以用來做一些網址的路由對應,要在 WP7 裡實現這樣的功能,請參考以下設定步驟:
1. 首先,我們先開起 App.xaml 檔案,並先新增一個 UriMapper 命名空間
xmlns:UriMapper="clr-namespace:System.Windows.Navigation;assembly=Microsoft.Phone"
如下圖示:
2. 在應用程式資源的區段 ( <Application.Resources> ) 加入一個 UriMapper 的定義,並且命名為 LoginPageMapper,而在其中唯一的一筆 UriMapper 定義裡有兩個屬性需要設定,一個 Uri 是屬性,用來定義比對的網址;另一個是 MappedUri 屬性,用來定義當網址比對成功後應該轉向到哪個網址。
<UriMapper:UriMapper x:Name="LoginPageMapper">
<UriMapper:UriMapping Uri="/MainPage.xaml"
MappedUri="/Login.xaml" />
</UriMapper:UriMapper>
3. 雖然已經定義了一筆 UriMapper 定義,並不代表 UriMapper 的規則已經正式啟用,這裡我們所建立的只是一個「應用程式資源」而已,所以還必須開啟 App.xaml.cs 並在 App() 建構子最後加上以下程式:
RootFrame.UriMapper = Resources["LoginPageMapper"] as UriMapper;
此時我們的 UriMapper 就正式生效了,如果你按下 F5 執行,就會發現首頁 ( MainPage.xaml ) 事實上並沒有被導向,而是網址被改寫 (Rewrite) 成 /Login.xaml 了,但我們看起來卻好像是被導向的感覺!
接下來就是如何靈活運用 UriMapper 的時刻,你可以在 App() 建構子透過程式碼動態修改 MappedUri 位址,好讓頁面能夠轉向 ( 雖然是改寫網址,但我還是寫轉向比較容易理解 ) 到其他頁面。
例如說以下程式碼,我可以讀取在隔離儲存區的應用程式設定中是否已經設定過 Username 這個鍵值,如果有的話我就視為此人已經登入過,並動態的把 MappedUri 屬性修改成 /MainPage.xaml 這個位址:
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 命名空間才行喔!
using System.IO.IsolatedStorage;
當然,你也可以定義多筆 UriMapper 定義,來宣告其他頁面的網址對應規則,或撰寫更複雜的判斷規則,如此一來整個 WP7 App 的各種頁面顯示前轉向的功能與判斷邏輯就可以集中管理,也不失為一種好方法。
今日修練總結
原來在 WP7 的開發模式裡,要實作出「頁面顯示前就轉向」也有這麼些學問,果然跟我們一般在做網頁開發時差異頗大。透過 UriMapper 的操作技巧著實非常方便,如能更深入研究 Silverlight 的巡覽框架 (Navigation Framework)相信還能有其他的體悟。
相關連結