2012-07-18 108 views
44

我試圖用C#創建一個UWP(通用Windows應用程序)應用程序。我的問題是Frame控件:如果我在沒有使用NavigationCacheMode = Required的情況下使用它,每次用戶返回時,頁面都不會保存在內存中,並且會被重新創建。如果我將NavigationCacheMode設置爲RequiredEnabled,則返回正常工作(無新頁面對象)但是如果我導航到來自同一類型的另一頁面,則上一頁面對象將被回收並重新使用(無新頁面實例)。WinRT/UWP框架和頁面緩存:如何在Navigate()上創建新頁面實例並將頁面實例保留在GoBack上()

期望的行爲:

有沒有辦法有一個與原來Frame控制以下行爲(如在Windows手機):

  1. Navigate()
  2. 不斷創建新的頁面實例頁面實例上GoBack()

我所知道的唯一的解決方案是創建一個自己的Frame控制,但是這會導致其他問題(如:缺少SetNavigationState()方法,等...)

示例場景:

用三頁的簡單應用實例:TvShowListPageTvShowDetailsPageSeasonDetailsPage

  1. TvShowListPage是入口頁面。點擊TvShow後導航至TvShowDetailsPage
  2. 現在TvShowDetailsPage在列表中選擇一個季節並導航到TvShowDetailsPage
  3. 如果返回,頁面應該留在內存中以避免重新加載頁面。
  4. 但是,如果用戶可以追溯到TvShowListPage並選擇另一TvShowTvShowDetailsPage得到回收,並可能在錯誤的狀態(例如顯示投支點,而不是第一個,季節樞)

我期待對於默認的Windows Phone 7行爲:導航在頁面堆棧上創建一個新頁面,然後從堆棧中刪除頂層頁面,並顯示堆棧中的前一頁(存儲在內存中)。

解決方案:

因爲沒有解決這個問題,我不得不重新實現所有分頁相關類:頁,框架,SuspensionManager等..

庫MyToolkit它提供了所有這些類可以在這裏下載:https://github.com/MyToolkit/MyToolkit/wiki/Paging-Overview

參考文獻:

+6

這可能是Windows 8上最惱人的事情之一。感謝您的解決方案! – 2013-08-29 17:30:30

回答

16

因爲沒有解決這個問題,我不得不重新實現所有分頁相關類:頁,框架,SuspensionManager等..

的解決方案可以在這裏下載: https://github.com/MyToolkit/MyToolkit/wiki/Paging-Overview

更新:

頁面類現在還提供了OnNavigatingFromAsync方法來顯示例如異步彈出,如果需要取消導航...

+0

我們是否必須使用HamburgerFrameBuilder中的漢堡項目,因爲我擁有自己的漢堡包,無論如何我都可以使用我的漢堡包嗎?像frame.goback和frame這樣簡單的東西。用mtPage作爲參數和參數導航? – AbsoluteSith 2016-02-29 12:17:09

+0

這不是強制性的,只需檢查GitHub頁面上的文檔或與我聯繫。 – 2016-02-29 21:35:17

+0

好吧,明白了!我有一個更多的疑問MtFrame.Navigate()只有一個參數,即;該頁面和無參數參數可以傳遞。如何將參數發送到導航頁面? – AbsoluteSith 2016-03-01 07:33:33

1

使用NavigationCacheMode屬性可以指定是否爲每次訪問頁面創建頁面的新實例,或者是否爲每次訪問使用了緩存中保存的頁面的以前構造的實例。

NavigationCacheMode屬性的默認值爲Disabled。當頁面的新實例對於每次訪問不是必需的時,將NavigationCacheMode屬性設置爲Enabled或Required。通過使用頁面的緩存實例,可以提高應用程序的性能並減少服務器的負載。

將NavigationCacheMode設置爲Required表示無論CacheSize屬性中指定的緩存頁面的數量如何,該頁面都被緩存。標記爲必需的頁面不計入CacheSize總數。將NavigationCacheMode設置爲Enabled意味着頁面被緩存,但如果緩存的頁面數量超過CacheSize的值,則可以處理該頁面。

如果必須爲每次訪問創建新實例,請將NavigationCacheMode屬性設置爲Disabled。例如,您不應該緩存顯示每個客戶獨有信息的頁面。

即使從緩存中檢索頁面,也會爲每個請求調用OnNavigatedTo方法。您應該在此方法中包含必須爲每個請求執行的代碼,而不是將該代碼放置在Page構造函數中。

+0

一切都正確,但這不是一個解決方案。你說唯一的方法是清理'OnNavigatedTo()'中的頁面(不是一個好的解決方案,因爲我有淡出圖像淡出第一等...)?正如我在答案中所看到的,我可以具有行爲1.或2.但不是兩者? – 2012-07-18 11:18:10

6

當你瀏覽向前,您可以設置NavigationCacheMode殘疾人你叫Frame.Navigate過嗎?然後,在OnNavigatedTo()集合NavigationCacheMode回到再次啓用

這應該是這樣,當你向前導航時,緩存被禁用。但是,當您到達新頁面實例時,OnNavigatedTo將再次啓用它。當您想要導航時,在撥打Frame.GoBack之前,您不會觸摸NavigationCacheMode。這應該給你緩存的實例,我認爲。

我相信這可行,但我還沒有測試過。我很想知道它是否確實如此。那裏有趣的場景。我很想看到該應用程序的行動,並更好地理解這種行爲的使用。

+0

謝謝,我會試試這個。看到我的更新的答案爲一個示例場景... – 2012-07-18 22:36:53

+3

它似乎沒有工作。一些發現:'NavigationCacheMode'必須在構造函數中設置才能生效。稍後更改屬性(在導航時不起作用)... – 2012-07-18 22:46:28

+0

這適用於我,您在哪裏閱讀過,它只能在構造函數中設置時才能生效? – user1512186 2015-07-07 07:41:32

8

我有很多相同的問題。我希望這樣,當我在Metro(Windows Store是正確的)中前進時,它會創建一個新實例。但是,返回時,它會保留我想要保存的數據。

所以,我同樣使用NavigationCacheMode = NavigationCacheMode.Enabled。我發現無論我前進還是後退,都保存着。所以,我會前進幾頁,然後退回幾頁。我希望所有事情都在我向前移動時重新設置,我總是發現它不是;它保留了這些數據。

我嘗試了一切,包括編寫我自己的後退按鈕代碼以包含NavigationCacheMode = NavigationCacheMode.Disabled,但無濟於事。正如其他人指出的那樣,一旦啓用它,NavigationCacheMode將不會被禁用。

我確實找到了解決方案。我去了La​​youtAwarePage.cs,只做了一些小改動。根據「OnNavigatedTo」,我發現該行:

// Returning to a cached page through navigation shouldn't trigger state loading 
if (this._pageKey != null) return; 

但是,評論與我想要的相反。我正在尋找單向模式下的狀態加載。如果前進,我想要加載狀態;如果向後移動,我想要註釋的行爲 - 沒有狀態加載。

所以我只是修改了這一行。

// Returning to a cached page through navigation shouldn't trigger state loading 
if (this._pageKey != null && e.NavigationMode == NavigationMode.Back) return; 

我已經測試過它,它完美地工作。現在,當向後導航時,它會記住狀態並保持頁面一致。前進,它載入新鮮。

也許不是最佳實踐,但我不會從我的代碼隱藏中調用「OnNavigatedTo」。我通過「LoadState」執行所有操作。如果您在代碼隱藏中重寫「OnNavigatedTo」,您可能會看到不同的行爲。

謝謝

約瑟夫·歐文

+1

中更改這是否也保留滾動位置等或只有你「手動保存」的狀態? – 2012-08-31 22:09:15

+0

剛剛測試過你的代碼 - 不起作用。 – 2012-09-28 09:58:30

+0

如何爲UWP應用程序實現此目的? – AbsoluteSith 2016-02-29 11:38:55

0

我不得不從我page類派生一個page2類,然後當我想瀏覽到同一頁的第二個版本,我檢測this對象是page還是page2。然後我導航到page2,如果我在page並導航到page如果在page2

唯一的缺點是巨大的缺點是無法從另一個派生一個XAML文件。因此,所有C#代碼都在page類的代碼隱藏中,但是有兩個幾乎相同的XAML文件,每個版本的頁面都有一個。

可能會添加一個小腳本作爲預生成步驟,從第一個生成第二個頁面類,複製XAML數據並調整類名稱。

這是醜陋的,但它幾乎完美,我從來不必擔心C#代碼重複或怪異的導航緩存問題。我只是最終得到了重複的XMAL代碼,這在我的情況下真的永遠不會改變。我還最終得到兩條警告,說明在自動生成的代碼page2.InitializeComponent()page2.Connect()上不使用new關鍵字。

有趣的是,導航到page然後page2然後page不會引起問題和page類的第二個實例是一個實際的第二個實例無關的第一。

請注意,此解決方案可能被MS推薦使用。

+0

我剛剛發現這適用於針對Windows 8.1的應用程序,但不適用於Windows 10的UWP應用程序。在UWP應用程序中,第2頁上的控件無法在第1頁的代碼隱藏中訪問。似乎是控件對象的多個實例,每個頁面一個。我無法解釋它,但調試器顯示兩個具有完全相同名稱的成員變量。我可能是錯誤的,因爲我剛剛將8.1應用程序轉換爲UWP應用程序,而我仍然發現這樣的小問題。可能仍然有解決方案。 – 2017-01-01 01:15:31

0

我所取得的:

  • 設置NavigationCacheMode到必需/啓用所需的頁面。
  • 在點擊第二頁上的按鈕/鏈接:

    導線框架返回堆棧,並找出如果第2頁在堆棧中。 如果找到Page2,則調用Frame.GoBack()所需的次數。 如果找不到,請導航到新頁面。 這將適用於任何頁面。

代碼示例:

public void Page2Clicked(object sender, RoutedEventArgs e) 
{ 
int isPresent = 0; 
int frameCount = 0; 
//traverse BackStack in reverse order as the last element is latest page 
for(int index= Frame.BackStack.Count-1; index>=0;index--) 
{ 
    frameCount += 1; 
    //lets say the first page name is page1 which is cached 
    if ("Page2".Equals(Frame.BackStack[index].SourcePageType.Name)) 
    { 
     isPresent = 1; 
     //Go back required no of times 
     while (frameCount >0) 
     { 
      Frame.GoBack(); 
      frameCount -= 1; 
     } 
     break; 
    } 

} 
    if (isPresent == 0) 
    { 
    Frame.Content = null; 
    Frame.Navigate(typeof(Page2)); 
    } 
} 

這將是有益的,如果前進/後退按鈕將不會使多大用處的。 ,因爲此解決方案將影響前進/後退導航。 如果您希望使用向前/向後導航,則需要處理一些其他情況。

相關問題