通常來說,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 頁面觸發。使用上必須覆寫此事件。
當 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();
}
所以在切換頁面前將資料寫入隔離區檔案儲存,在另一個頁面時讀取,就完成了資料傳遞。
我要留言
留言小提醒:
1.回覆時間通常在晚上,如果太忙可能要等幾天。
2.請先瀏覽一下其他人的留言,也許有人問過同樣的問題。
3.程式碼請先將它編碼後再貼上。(線上編碼:http://bit.ly/1DL6yog)
4.文字請加上標點符號及斷行,難以閱讀者恕難回覆。
5.感謝您的留言,您的問題也可能幫助到其他有相同問題的人。