2012年9月14日 星期五

取得 Page 的返回值

在應用程式的寫作流程上,難免有些情況必須用到 Dialog 這種對話視窗,
但 Windows Phone 上僅能用 PhoneApplicationPage 的方式來製作對話流程,
傳統上 Dialog 在被關閉後是可以做傳回值的,或是在其被釋放之前可以繼續調用需要的值,

利用 Page 做對話流程的情況下,就目前所知沒辦法這麼做,因為那些 Page 不屬於任何母視窗,
大多數情況我們在 Page1 中開啟 Page2 詢問用戶一些選項後,
若在 Page2 按上一頁回到 Page1 時,以往的方式大多會想到用以下方式來儲存資訊,

((App)Application.Current).AppGlobalData = "用戶選了男性、O型、台北人";

// 或

PhoneApplicationService.Current.State["AppGlobalData"] = "用戶選了男性、O型、台北人";

然後在 Page1 的 OnPageLoaded 時將資料取出來顯示,這種方式沒什麼不好的,
但畢竟這兩種方式是使用全域的成員,若對話流程很多,全域的變數或設定相對的也會多很多,
且我們沒辦法比較單純的將一個頁面才需要用到的資料獨立整理。

其實觀察 OnNavigatedFrom 可以發現 NavigationEventArgs 參數中有些資訊可以用,
OnNavigatedFrom 是發生在當頁面導向新 Page 完成後的事件,
而這之中的 NavigationEventArgs.Content 就是這頁新的 Page Instance,
所以可以將 e.Content 轉型為 Page 後對之中的成員做給值的動作,
以上面的例子來看,只要在 Page1 中宣告一個適當的成員變數,
Page2 在 OnBackKeyPress 回到 Page1 時可以利用這種方式將資訊設給此變數,
如此即不需在 App 類別中或 PhoneApplicationService 針對單一頁面建立多個成員變數,
下面我寫了一個範例示範如何在 Page2 中將資訊設值給 Page1 的成員變數,
在範例中,另外寫了將值設給 Page3 的流程,Page3 為 Page2 的下一頁,
在 Windows Phone 中導覽某頁僅能利用類似 get 參數的方式傳遞字串參數,
字串以外的方式還是得利用上述的 App Instance 或 PhoneApplicationService 的方式,
利用 OnNavigatedFrom 這點即可在頁面導覽之間分享字串以外的類別。

public partial class Page2 : PhoneApplicationPage
{
    public Page2()
    {
        InitializeComponent();
    }

    protected override void OnNavigatedFrom(NavigationEventArgs e)
    {
        Type typeofTargt = e.Content.GetType();
        if (typeof(Page3) == typeofTargt)
        {
            // 對下一頁的某屬性設值當作傳遞參數
            ((Page3)(e.Content)).NavigationParam = "i am page 2";
        }
        else if (typeof(Page1) == typeofTargt)
        {
            // 對上一頁的某屬性設值當作回傳結果
            ((Page1)(e.Content)).NavigationResult = "result ok";
        }
        base.OnNavigatedFrom(e);
    }
}

而 Page3 中只要在 OnPageLoaded 中查詢 NavigationParam 是否為 null
即可知道導覽至自己的上一頁是否有帶資訊過來,並對其做對應的處理即可,
在此雖然是使用 PhoneApplicationPage 做範例,但在 Windows Metro App 中也是適用的,
Metro App 中導覽至新的一頁雖然可以帶 Object 參數,但 Back 時不行,
我們只好利用同樣的方式在 OnNavigatedFrom 中做處理對上一頁的變數設值來達到目的,
比較起來 Android 的 startActivityForResult 與 onActivityResult 實在方便很多。

public partial class Page3 : PhoneApplicationPage
{
    public Object NavigationParam = null;

    public Page3()
    {
        InitializeComponent();
        this.Loaded += OnPageLoaded;
    }

    private void OnPageLoaded(object sender, RoutedEventArgs e)
    {
        if(NavigationParam == null)
        {
            // 沒有預設參數時的載入行為
        }
        else
        {
            Debug.WriteLine((String)NavigationParam); // 印出 i am page 2
        }
    }
}

沒有留言:

張貼留言