Windows Phone 學習筆記 (4) – 頁面切換及傳值

  • 3563
  • 0

多頁面 App 的製作及頁面間資料的傳遞。

 

 Photo by appboy.com

 

(本文於 http://blog.tonycube.com 同步發表)

 

§ 多頁面應用程式

通常來說,App 不會只有一個頁面,可能會有兩個或多個頁面,所以我們要瞭解如何做到頁面的切換。當需要頁面切換時,有些時候需要將使用者所選擇的資料傳遞給下一個頁面,這時候就必須瞭解如何處理資料傳遞。

 

假設啟動頁面為 MainPage.xaml,我們新增了一個結果頁面叫ResultPage.xaml,那要如何從 MainPage.xaml 切換到 ResultPage.xaml 呢?

 

在 MainPage.xaml 中我新增了一個按鈕,當按下時就會切換到結果頁面,按鈕中只要寫下:

 

NavigationService.Navigate(new Uri("/ResultPage.xaml", UriKind.Relative));

 

NavigationService 是一個專門用來做導覽服務的類別,使用其中的 Navigate 方法即可將頁面導向我們要的頁面。Uri 類別中有兩個輸入參數,第 1 個是我們要前往的頁面檔名,第 2 個則是我們要對第 1 個參數使用絕對路徑或相對路徑。

 

通常在切換頁面時會使用相對路徑,也就是「/ + 檔案名稱」,斜線表示為同一目錄,所以假設頁面是在 view 目錄之下,那就必須寫成「/view/ResultPage.xaml」。

 

UriKind還有另一個 Absolute 可選,表示路徑為絕對路徑,通常會用在取得網路上的資料,例如:http://abc.com/image.png 之類的檔案,這時候就要使用絕對路徑。  

 

§ 頁面切換事件

在做頁面切換時會觸發幾個事件:

  • Loaded
    在每次頁面載入完成時觸發。
  • Unloaded
    要從目前頁面切換到另一個頁面時觸發。
  • OnNavigatedFrom
    利用 NavigationService 從 A 頁面切換到 B 頁面時,在 A 頁面觸發。使用上必須覆寫此事件。
  • OnNavigatedTo
    利用 NavigationService 從 A 頁面切換到 B 頁面時,在 B 頁面觸發。使用上必須覆寫此事件。

我在兩個頁面(MainPage.xaml, ResultPage.xaml)中的這4個事件中分別輸出資料到Console中來看看事件的運作順序。

 

當 App 第 1 次開啟載入 MainPage.xaml 時,觸發 2 個事件:

 

MainPage: OnNavigatedTo
MainPage: Loaded

 

接著按下 MainPage.xaml 中的按鈕,前往 ResultPage.xaml,觸發的事件依序為:

 

MainPage: OnNavigatedFrom
ResultPage: OnNavigatedTo
MainPage: Unloaded
ResultPage: Loaded

 

再按下實體返回鍵,回到MainPage.xaml:

 

ResultPage: OnNavigatedFrom
MainPage: OnNavigatedTo
ResultPage: Unloaded
MainPage: Loaded

 

如此可以很清楚看到切換頁面的事件觸發順序。 但這裡有點要注意,有時候我們會在 OnNavigatedTo 事件取得前一頁面傳來的值。假設我們有 3 個頁面分別為 A, B, C。從 A 到 B 會觸發 B 的 OnNavigatedTo ,接著我們從 B 到 C,然後又返回 B ,會怎樣呢?會正常的觸發一次 B 的 OnNavigatedTo ,這在不傳遞資料的情況下不會有問題,但若 B 會接收 A 所傳來的資料,當使用者從 C 退回 B 時也會觸發 B 的 OnNavigatedTo ,可是因為是從 C 退回來的而不是 A ,所以若在 B 中接收資料,就可能產生錯誤,所以這部份記得要做好處理。或是利用別種傳遞資料的方式。  

 

§ 資料傳遞

傳資料的方式有很多種,適情況選擇適合的方式,這裡列出 4 種方式:

  • 全域變數
  • Url參數
  • PhoneApplicationSerivce 中的 State 屬性
  • Isolated storage(永久性儲存)

 

※全域變數

利用 App 類別 (App.xaml.cs 檔),在該類別中新增 static 變數來做儲存,接著在呼叫 NavigationService.Navigate() 之前,先把資料存入這個 static 變數。然後在新頁面中 OnNavigatedTo 事件中取出這個 static 變數來使用。

 

利用全域變數的傳遞方式,該變數在整個App中的任何類別中都可以取用。  

 

※Url參數

這個方式的使用和網址後面常看到的一串query字串一樣,所以寫起來會像是:

 

ResultPage.xaml?msg=hello&count=1

 

在 ResultPage.xaml 中的 OnNavigatedTo 接收時這麼寫:

 

Debug.WriteLine(NavigationContext.QueryString["msg"]);
Debug.WriteLine(NavigationContext.QueryString["count"]);

 

很簡單吧~~傳值時,在頁面後的第一個參數用問號 (?) 之後每個都用 (&) 來分隔。

 

※PhoneApplicationSerivce 中的 State 屬性

這個方式和全域方式有點像,因為整個 App 都可以取用,但我們不用 App 類別,而是利用 PhoneApplicationSerivce 的 State 屬性。

 

State 是一個實做 IDictionary 的類別,可以用來保存應用程式的相關資料。IDictionary是以一個鍵值對的方式來儲存資料,也就一個key會有一個對應的value。 使用時,必須先引用 Microsoft.Phone.Shell 的命名空間。

在當前頁面中這麼寫

 

PhoneApplicationService.Current.State["msg"] = "hello";

 

一樣在切換的頁面的 OnNavigatedTo 事件中寫:

 

object data = null; 
if (PhoneApplicationService.Current.State.TryGetValue("msg", out data))
     textBox1.Text = (string)data; 
else     
     textBox1.Text = "error";

 

使用TryGetValue是為了防止要取得的 key 不存在,若 key 不存在會發生錯誤。如果將資料保存在 State 中,那麼除非應用程式結束,不然在 Deactivated、Activated 事件中,這些資料都還會保留下來。

 

※Isolated storage(永久性儲存)

Isolated storage 中文為隔離儲存區,每個 App 有自己的隔離儲存區,其他 App 無法取用,儲存在這裡的資料不會因為 App 關閉或手機關機而消失。 使用時必須引用 System.IO.IsolatedStorage 及 System.IO 命名空間。

 

寫入檔案:

 

IsolatedStorageFile isofile = IsolatedStorageFile.GetUserStoreForApplication(); 
if (isofile.FileExists("/data.txt"))
     isofile.DeleteFile("/data.txt"); 

StreamWriter sw = new StreamWriter(isofile.CreateFile("/data.txt"), System.Text.Encoding.UTF8); 
sw.WriteLine("要儲存的資料"); 
sw.Close(); 
sw.Dispose(); 
isofile.Dispose();

 

基本上就只是將資料寫入 data.txt 檔。

 

讀取檔案:

 

IsolatedStorageFile isofile = IsolatedStorageFile.GetUserStoreForApplication(); 
if (isofile.FileExists("/data.txt")) {
     StreamReader sr = new StreamReader(isofile.OpenFile("/data.txt", FileMode.Open), System.Text.Encoding.UTF8);
     string tmpString = sr.ReadLine();
     sr.Close();
     sr.Dispose();
     isofile.Dispose(); 
} 

 

所以在切換頁面前將資料寫入隔離區檔案儲存,在另一個頁面時讀取,就完成了資料傳遞。

 

※總結

Isolated storage用來傳遞資料其實有點大材小用,因為它能做的事情太多了,通常會用來儲存像是圖片或檔案等必須永久性儲存的資料。全域性的資料儲存建議只有整個 App 會用到的才使用此方式,比較不容易因為某個地方改變了資料而產生錯誤。資料量少的話用url來傳是最方便的,也是大部份情況下會用到的方式。