it-swarm.com.ru

WinRT/UWP Кэширование кадров и страниц: как создать новый экземпляр страницы в Navigate () и сохранить экземпляр страницы в GoBack ()

Я пытаюсь создать приложение UWP (универсальное приложение для Windows) с помощью C #. Моя проблема заключается в элементе управления Frame: если я использую его без NavigationCacheMode = Required, каждый раз, когда пользователь возвращается, страница не сохраняется в памяти и будет создаваться заново. Если я установлю для NavigationCacheMode значение Required или Enabled, возврат будет работать правильно (без объекта новой страницы) , но если я перейду на другую страницу того же типа, объект предыдущей страницы будет переработан и повторно использован (без нового экземпляра страницы). 

Желаемое поведение:

Есть ли способ иметь следующее поведение с оригинальным элементом управления Frame (как в Windows Phone): 

  1. Создать новый экземпляр страницы на Navigate()
  2. Сохранить экземпляр страницы на GoBack() 

Единственное известное мне решение - создать собственный элемент управления Frame, но это приводит к другим проблемам (например, отсутствует метод SetNavigationState() и т.д.)

Пример сценария:

Простой пример приложения с тремя страницами: TvShowListPage, TvShowDetailsPage, SeasonDetailsPage

  1. TvShowListPage это страница входа. После нажатия на TvShow перейдите к TvShowDetailsPage
  2. Теперь в TvShowDetailsPage выберите сезон в списке и перейдите к TvShowDetailsPage
  3. При переходе назад страницы должны оставаться в памяти, чтобы избежать перезагрузки страниц. 
  4. Но если пользователи возвращаются к TvShowListPage и выбирают другую TvShow, TvShowDetailsPage перерабатывается и, возможно, находится в неправильном состоянии (например, показывает переднюю точку приведения вместо первой, сезонную точку)

Я ищу поведение Windows Phone 7 по умолчанию: при навигации создается новая страница в стеке страниц, при возврате происходит удаление верхней страницы из стопки и отображение предыдущей страницы из стопки (сохраненной в памяти). 

Решение:

Поскольку решения этой проблемы не было, мне пришлось переопределить все соответствующие классы подкачки: Page, Frame, SuspensionManager и т.д. 

Library MyToolkit, которая предоставляет все эти классы, может быть загружена здесь: https://github.com/MyToolkit/MyToolkit/wiki/Paging-Overview

Рекомендации:

45
Rico Suter

Поскольку решения этой проблемы не было, мне пришлось переопределить все соответствующие классы подкачки: Page, Frame, SuspensionManager и т.д. 

Решение можно скачать здесь: https://github.com/MyToolkit/MyToolkit/wiki/Paging-Overview

Обновление:

Класс страницы теперь также предоставляет метод OnNavigatingFromAsync для отображения, например, всплывающего окна асинхронного режима и отмены навигации при необходимости ...

16
Rico Suter

У меня была такая же проблема. Я хотел, чтобы, когда я двигался вперед в Metro (Windows Store, чтобы быть подходящим), он создавал новый экземпляр. Однако, возвращаясь, он сохранит данные, которые я хотел сохранить.

Итак, я также использовал NavigationCacheMode = NavigationCacheMode.Enabled. Я обнаружил, что независимо от того, каким путем я шел, вперед или назад, все всегда сохранялось. Итак, я бы прошел вперед на несколько страниц, а затем отступил на несколько. Надеясь, что все было сброшено, когда я шел вперед, я неизменно обнаруживал, что это не так; он сохранил данные.

Я перепробовал все, включая написание своего собственного кода кнопки возврата, чтобы включить NavigationCacheMode = NavigationCacheMode.Disabled, но безрезультатно. Как уже отмечали другие, как только вы включите его, NavigationCacheMode просто не будет отключен.

Я нашел решение. Я пошел в LayoutAwarePage.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" в коде позади, вы можете увидеть другое поведение.

Спасибо,

Джозеф Ирвин

8
jkeagle13

Когда вы перемещаетесь по forward, можете ли вы установить NavigationCacheMode to Disabled перед вызовом Frame.Navigate ? Затем в OnNavigatedTo () set NavigationCacheMode обратно в включено снова.

Это должно сделать так, чтобы при переходе вперед кэширование было отключено. Но когда вы прибудете на новый экземпляр страницы, OnNavigatedTo включит его снова. Если вы хотите вернуться назад, вы не будете касаться NavigationCacheMode перед вызовом Frame.GoBack . Это должно дать вам кешированный экземпляр, я думаю.

Я верю, что это будет работать, но я не проверял это. Мне было бы интересно узнать, если это так. Интересный сценарий есть. Я хотел бы видеть приложение в действии и лучше понять использование этого поведения.

6
Jared Bienz - MSFT

Вы используете свойство NavigationCacheMode, чтобы указать, создается ли новый экземпляр страницы для каждого посещения страницы или для каждого посещения используется ранее созданный экземпляр страницы, который был сохранен в кэше.

Значением по умолчанию для свойства NavigationCacheMode является Отключено. Установите для свойства NavigationCacheMode значение «Включено» или «Требуется», если новый экземпляр страницы не важен для каждого посещения. Используя кэшированный экземпляр страницы, вы можете повысить производительность вашего приложения и снизить нагрузку на ваш сервер.

Если для NavigationCacheMode установлено значение Required, страница кэшируется независимо от количества кэшированных страниц, указанного в свойстве CacheSize. Страницы, помеченные как Обязательные, не учитываются в общем объеме CacheSize. Если для NavigationCacheMode установлено значение «Включено», страница кэшируется, но она может быть удалена, если число кэшированных страниц превышает значение CacheSize.

Установите для свойства NavigationCacheMode значение Disabled, если для каждого посещения должен быть создан новый экземпляр. Например, вы не должны кэшировать страницу, которая отображает информацию, уникальную для каждого клиента.

Метод OnNavigatedTo вызывается для каждого запроса, даже когда страница извлекается из кэша. Вы должны включить в этот метод код, который должен выполняться для каждого запроса, а не помещать этот код в конструктор Page.

2
Magi

Я достиг этого путем:

  • Установка NavigationCacheMode на Обязательный/Включен для обязательных страниц.
  • При нажатии на кнопку/ссылку Page2:

    Пройдите через Frame BackStack и выясните, находится ли Page2 в BackStack . Если 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));
    }
}

Это будет полезно, если кнопки «вперед» и «назад» не будут широко использоваться ………., Поскольку это решение повлияет на навигацию вперед/назад…. Если вы также хотите использовать навигацию вперед/назад, то некоторые дополнительные случаи должен быть обработан.

0
Mithilesh Gupta

Мне пришлось извлечь класс page2 из моего класса page, а затем, когда я хочу перейти ко второй версии той же страницы, я определяю, является ли объект thispage или page2. Затем я перехожу к page2, если я был в page, и перехожу к page, если в page2.

Единственный недостаток, который является огромным, заключается в том, что нет способа извлечь один файл XAML из другого. Таким образом, весь код C #, как и ожидалось, находится в выделенном коде класса page, но есть два почти идентичных файла XAML, по одному для каждой версии страницы.

Небольшой сценарий, вероятно, можно добавить в качестве шага перед сборкой, чтобы сгенерировать второй класс страницы из первого, скопировав данные XAML и скорректировав имена классов.

Это уродливо, но почти идеально работает, и мне никогда не придется беспокоиться о дублировании кода C # или странных проблемах с кешем навигации. Я просто получаю дубликат XMAL-кода, который в моем случае действительно никогда не меняется. Я также получаю два предупреждения о неиспользовании ключевого слова new в автоматически сгенерированном коде для page2.InitializeComponent() и page2.Connect().

Интересно, что переход к page, затем к page2, а затем к page не вызывает проблем, и второй экземпляр класса page является фактическим вторым экземпляром, не связанным с первым.

Обратите внимание, что это решение, вероятно, рекомендуется против MS.

0
David Rector