Восстановление данных сессии

Последнее обновление: 31.10.2015

В предыдущей теме мы сохраняли и обратно загружали в программу текст для текстового поля с помощью объекта Windows.Storage.ApplicationData. Такие данные представляют данные приложения. Но кроме них в приложении имеются еще и данные сеанса.

Данные сеанса являются временными и относятся к текущему сеансу. Если пользователь закрывает приложения, нажав на крестик, то он тем самым завершает сеанс. При этом данные приложения сохраняются, и могут быть восстановлены. А вот данные сеанса будут уже другие. Такое поведение нежелательно в некоторых случаях.

Итак, возьмем проект приложения LifecycleApp из прошлой темы. В нем уже есть страница Page1. Изменим файл Page1.xaml следующим образом:

<Page
    x:Class="LifecycleApp.Page1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:LifecycleApp"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">

    <Grid x:Name="LayoutRoot">
        <StackPanel>
            <TextBlock Text="Страница 1" Style="{ThemeResource HeaderTextBlockStyle}" />
            <Button Content="На страницу 2" Click="Button_Click" />
            <TextBox x:Name="inputBox" />
        </StackPanel>
    </Grid>
</Page>

Здесь опять же текстовое поле, а также кнопка для перехода на другую страницу. В итоге получится следующий дизайн:

И также добавим в файл Page1.xaml.cs обработчик нажатия кнопки, по которому будет идти переход на вторую страницу:

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

Теперь добавим саму вторую страницу. Это будет добавление нового элемента по типу Basic Page, и назовем его Page2

В файле Page2.xaml определим следующую разметку:

<Page
    x:Class="LifecycleApp.Page2"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:LifecycleApp"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">

    <Grid x:Name="LayoutRoot">
        <StackPanel>
            <TextBlock Text="Страница 2" Style="{ThemeResource HeaderTextBlockStyle}" />
            <Button Content="На страницу 1" Click="Button_Click" />
        </StackPanel>
    </Grid>
</Page>

А в файле кода Page2.xaml.cs определим обработчик кнопки, который бы переходил обратно на первую страницу:

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

Теперь если мы запустим приложение, перейдем с первой страницы на вторую. И если мы сделаем Suspend and shutdouwn, то приложение вновь запустится с первой страницы. То есть данные о навигации не сохраняются. Подобным образом если ввести что-то в текстовое поле и перезагрузить приложение, то данные опять не сохраняться.

Чтобы сохранить, а затем восстановить данные сеанса, нам потребуется класс SuspensionManager, который добавляется в проект в папку Common вместе с добавлением первого элемента Basic Page.

Вся основная работа по сохранению данных проводится в коде класса App, поэтому откроем файл App.xaml.cs. Поскольку работа приложения начинается с метода OnLaunched, то в нем нам надо определить загрузку данных сеанса. И для этого изменим этот метод следующим образом:

protected async override void OnLaunched(LaunchActivatedEventArgs e)
{
	Frame rootFrame = Window.Current.Content as Frame;

    // убедимся, что объект Window уже имеет содержимое
    if (rootFrame == null)
    {
        // создаем объект Frame для выполнения навигации
        rootFrame = new Frame();

		// регистрация фрейма
        LifecycleApp.Common.SuspensionManager.RegisterFrame(rootFrame, "appFrame");
        
		rootFrame.CacheSize = 1;

        if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
        {
            // если приложение было завершено операционной системой, восстанавливаем его состояние
            await LifecycleApp.Common.SuspensionManager.RestoreAsync();
        }

        // помещаем фрейм в текущий объект Window
        Window.Current.Content = rootFrame;
    }

    if (rootFrame.Content == null)
    {
        if (rootFrame.ContentTransitions != null)
        {
            this.transitions = new TransitionCollection();
            foreach (var c in rootFrame.ContentTransitions)
            {
                this.transitions.Add(c);
            }
        }
		rootFrame.ContentTransitions = null;
        rootFrame.Navigated += this.RootFrame_FirstNavigated;

        if (!rootFrame.Navigate(typeof(Page1), e.Arguments))
        {
            throw new Exception("Failed to create initial page");
        }
    }

    // убедимся, что текущий объект Window является активным
    Window.Current.Activate();
}

Ключевым компонентом для отображения приложения на экране является объект Window, который определяется с помощью свойства Window.Current. Для загрузки отдельных страниц в окно Window нам нужен объект Frame, который позволяет переключаться между страницами, хранит историю навигации. Поэтому нам надо проверить, а определен ли уже такой объект Frame, и если неопределен - то создать его и добавить в Window. Для получения объекта Frame используется выражение Frame rootFrame = Window.Current.Content as Frame.

При создании объекта Frame нам надо зарегистрировать его: LifecycleApp.Common.SuspensionManager.RegisterFrame(rootFrame, "appFrame"). Тем самым мы указываем классу SuspensionManager какой именно фрейм будет в случае необходимости будет приостановлен, если приложение перейдет в состояние Suspended.

И если приложение было приостановлено, а затем завершено операционной системой, то мы восстанавливаем его состояние:

if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
{
    await LifecycleApp.Common.SuspensionManager.RestoreAsync();
}

В самом конце метода окно активируется, если оно не является активным: Window.Current.Activate()

Теперь изменим метод OnSuspending, срабатывающий при приостановке работы приложения. В нем мы будем сохранять данные:

private async void OnSuspending(object sender, SuspendingEventArgs e)
{
    var deferral = e.SuspendingOperation.GetDeferral();
    await LifecycleApp.Common.SuspensionManager.SaveAsync();
	deferral.Complete();
}

В отличие от кода по умолчанию здесь добавлена одна строка для асинхронной загрузки данных: LifecycleApp.Common.SuspensionManager.SaveAsync()

Этого хватит, чтобы сохранить и восстановить данные сеанса, например, историю навигации. И если мы перейдем с первой страницы на вторую и сделаем Suspend and shutdown, то при перезапуске окажемся опять же на второй странице.

Но это еще не все. У нас на первой странице Page1 есть текстовое поле. В прошлой теме его данные сохранялись как данные приложения через Windows.Storage.ApplicationData. Сейчас же сохраним его данные как данные сеанса. В файле кода Page1.xaml.cs у нас уже определены методы NavigationHelper_LoadState и NavigationHelper_SaveState, которые призваны загружать и сохранять соответственно данные сеанса для элементов правления. Изменим их следующим образом:

private void NavigationHelper_LoadState(object sender, LoadStateEventArgs e)
{
    if (e.PageState != null && e.PageState.ContainsKey("value"))
        inputBox.Text = e.PageState["value"].ToString();
}

private void NavigationHelper_SaveState(object sender, SaveStateEventArgs e)
{
    e.PageState["value"] = inputBox.Text;
}
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850