Подтвердить что ты не робот

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

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

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

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

  • Создайте экземпляр новой страницы в Navigate()
  • Храните экземпляр страницы в GoBack()

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

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

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

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

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

Решение:

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

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

Литература:

4b9b3361

Ответ 1

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

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

Update:

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

Ответ 2

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

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

Я попробовал все, включая написание собственного кода кнопки обратной связи, чтобы включить 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" в коде, вы можете увидеть другое поведение.

Спасибо,

Джозеф Ирвин

Ответ 3

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

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

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

Ответ 4

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

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

Настройка NavigationCacheMode в Required означает, что страница кэшируется независимо от количества кэшированных страниц, указанных в свойстве CacheSize. Страницы, помеченные как "Обязательные", не учитываются в общей сумме CacheSize. Установка NavigationCacheMode в Enabled означает, что страница кэшируется, но она имеет право на удаление, если количество кэшированных страниц превышает значение CacheSize.

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

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

Ответ 5

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

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

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

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

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

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

Ответ 6

Я достиг этого:

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

    Поверните рамку BackStack и узнайте, находится ли страница 2 в 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));
    }
}

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