2014年7月31日 星期四

NavigationCacheMode

NavigationCacheMode 是在撰寫 Store Apps 的過程非常重要的一個 Property,它位於 Page class 之中,對於學習 Universal Apps 時,在 Win 8.1 與 Phone 8.1 的概念是一模一樣的,但是該如何使用卻是從建立一個新的 Page 時,就可以從預設值發現兩個平台對於 NavigationCacheMode 的差異。

在建立 Universal Apps 時,各自打開 Win  與 Phone Project 的 MainPage.xaml.cs 可以發現到 Phone Project 的 MainPage.xaml.cs 在 Constractor 多了一行

NavigationCacheMode = NavigationCacheMode.Required;

而這行在 Win Project 的 MainPage.xaml.cs 卻沒有,我們先把這行移除,並新增兩個頁面分別為 SecondPage 與 ThirdPage 試試,再來我們加入簡單的 Code 讓這三個 Page 可以互相導覽到彼此。

MainPage.xaml.cs

public sealed partial class MainPage : Page
{
    public MainPage()
    {
        this.InitializeComponent();
        Debug.WriteLine("● ● ● Main Page Construct :: " + this.GetHashCode());
    }

    ~MainPage()
    {
        Debug.WriteLine("○ ○ ○ Main Page DeConstruct :: " + this.GetHashCode());
    }

    private void PageLoaded(object sender, RoutedEventArgs e)
    {
        Debug.WriteLine("MainPage OnLoaded");
    }

    private void PageUnloaded(object sender, RoutedEventArgs e)
    {
        Debug.WriteLine("MainPage Unloaded");
    }
    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
        Debug.WriteLine("MainPage OnNavigatedTo");
    }

    protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
    {
        base.OnNavigatingFrom(e);
        Debug.WriteLine("MainPage OnNavigatingFrom");
    }

    protected override void OnNavigatedFrom(NavigationEventArgs e)
    {
        base.OnNavigatedFrom(e);
        Debug.WriteLine("MainPage OnNavigatedFrom");
    }

    private void GoSecondPage(object sender, RoutedEventArgs e)
    {
        Frame.Navigate(typeof(SecondPage));
    }
}

SecondPage.xaml.cs

public sealed partial class SecondPage : Page
{
    public SecondPage()
    {
        this.InitializeComponent();
        Debug.WriteLine("● ● ● Second Page Construct :: " + this.GetHashCode());
    }

    ~SecondPage()
    {
        Debug.WriteLine("○ ○ ○ Second Page DeConstruct :: " + this.GetHashCode());
    }

    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
        Debug.WriteLine("SecondPage OnNavigatedTo");
    }

    protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
    {
        Debug.WriteLine("SecondPage OnNavigatingFrom");
        base.OnNavigatingFrom(e);
    }

    protected override void OnNavigatedFrom(NavigationEventArgs e)
    {
        Debug.WriteLine("SecondPage OnNavigatedFrom");
        base.OnNavigatedFrom(e);
    }

    private void PageLoaded(object sender, RoutedEventArgs e)
    {
        Debug.WriteLine("SecondPage OnLoaded");
    }

    private void PageUnloaded(object sender, RoutedEventArgs e)
    {
        Debug.WriteLine("SecondPage Unloaded");
    }

    private void GoThirdPage(object sender, RoutedEventArgs e)
    {
        Frame.Navigate(typeof(ThirdPage));
    }

    private void GoBack(object sender, RoutedEventArgs e)
    {
        Frame.GoBack();
    }
}

ThirdPage.xaml.cs

public sealed partial class ThirdPage : Page
{
    public ThirdPage()
    {
        this.InitializeComponent();
        Debug.WriteLine("● ● ● Third Page Construct :: " + this.GetHashCode());
    }

    ~ThirdPage()
    {
        Debug.WriteLine("○ ○ ○ Third Page DeConstruct :: " + this.GetHashCode());
    }

    private void GoBack(object sender, RoutedEventArgs e)
    {
        Frame.GoBack();
    }
}

在三個 Page 都將 NavigationCacheMode 拿掉的情況下,我們走一遍 MainPage -> SecondPage -> ThirdPage -> Back -> Back 的流程可以得到以下 Log

● ● ● Main Page Construct :: 60345850
MainPage OnNavigatedTo
MainPage OnLoaded
MainPage OnNavigatingFrom
● ● ● Second Page Construct :: 59535667
MainPage OnNavigatedFrom
SecondPage OnNavigatedTo
SecondPage OnLoaded
MainPage Unloaded
SecondPage OnNavigatingFrom
● ● ● Third Page Construct :: 38307039
SecondPage OnNavigatedFrom
SecondPage Unloaded
● ● ● Second Page Construct :: 58892413
SecondPage OnNavigatedTo
SecondPage OnLoaded
SecondPage OnNavigatingFrom
● ● ● Main Page Construct :: 9040679
SecondPage OnNavigatedFrom
MainPage OnNavigatedTo
MainPage OnLoaded
SecondPage Unloaded

由印出來的 Hash 可以發現每次進到頁面時,不論是新的頁面還是曾經到訪過的頁面,都會建立新的 Instance,這代表著原本 MainPage 上如果有 TextBox 記錄著用戶輸入的資訊,或是有 Timer 在跑經過的秒數,在 Back 回來後資訊會消失,計時會重來。

這時我們再把三個 Page 的 NavigationCacheMode 都加回去,可以加在 Constractor 中也可以在 XAML 中修改 Page 的 NavigationCacheMode Property 如下

public MainPage()
{
    this.InitializeComponent();
    NavigationCacheMode = NavigationCacheMode.Required;
    Debug.WriteLine("● ● ● Main Page Construct :: " + this.GetHashCode());
}

public SecondPage()
{
    this.InitializeComponent();
    NavigationCacheMode = NavigationCacheMode.Required;
    Debug.WriteLine("● ● ● Second Page Construct :: " + this.GetHashCode());
}

public ThirdPage()
{
    this.InitializeComponent();
    NavigationCacheMode = NavigationCacheMode.Required;
    Debug.WriteLine("● ● ● Third Page Construct :: " + this.GetHashCode());
}

// 或是撰寫在 XAML 中

<Page
    x:Class="NavModePractice.ThirdPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:NavModePractice"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
    NavigationCacheMode="Required"> <!-- 加入此行 -->

    <StackPanel HorizontalAlignment="Center">
        <TextBlock Text="I'm Third Page" FontSize="40"/>
        <Button Content="Click Me to go Back" Click="GoBack"/>
    </StackPanel>
</Page>

我們再用同樣的流程走一遍,在三個頁面皆加上 NavigationCacheMode = Required 後,印出來的 Log 如下

● ● ● Main Page Construct :: 60345850
MainPage OnNavigatedTo
MainPage OnLoaded
MainPage OnNavigatingFrom
● ● ● Second Page Construct :: 59535667
MainPage OnNavigatedFrom
SecondPage OnNavigatedTo
SecondPage OnLoaded
MainPage Unloaded
SecondPage OnNavigatingFrom
● ● ● Third Page Construct :: 38307039
SecondPage OnNavigatedFrom
SecondPage Unloaded
SecondPage OnNavigatedTo
SecondPage OnLoaded
SecondPage OnNavigatingFrom
SecondPage OnNavigatedFrom
MainPage OnNavigatedTo
MainPage OnLoaded
SecondPage Unloaded

可以發現頁面不再被重建了,這在 Phone Device 這種資源相對低的環境上,這個機制是相當重要的,並不是說 Windows Store Apps 就不需要針對 CacheMode 做修改,如果某幾頁例如首頁,我們不想儲存下任何東西,也不想讓用戶每次回來都必須重新從遠端取一次 Content 時,設定 CacheMode 為 Required 或 Enabled 是個方便的作法。

至於 NavigationCacheMode 的三個列舉值是什麼意思,官方文件說明得很清楚嘍:Page.NavigationCacheMode Property

NavigationCacheMode.Disabled:預設值,不做任何 Cache
NavigationCacheMode.Required:強制在 Frame 內 Cache Page
NavigationCacheMode.Enabled:由 Frame 自行管理 Cache 並依情況釋放

這些示範不僅表現出 Phone 8.1 XAML Apps 框架與 Siliverlight 框架在頁面生命週期的差異,也可以看出頁面的導覽不再是透過 NavigationService 而是 Frome 這個 Object,近期會再針對這點寫篇記錄。



沒有留言:

張貼留言