Сегодня мы поговорим о том, как хранить настройки в Windows 8 приложениях. Причем рассмотрим примеры хранения настроек локально и в сетевом хранилище.
Итак, в Metro Style приложениях вы можете хранить настройки программы как локально на устройстве (например позиционирование элементов под конкретное разрешение), так и в облаке, в этом случае доступ будет со всех устройств пользователя (например можно хранить рекорд пользователя).
В рамках первого примера, рассмотрим сохранение одиночных значений в локальном хранилище. Для демонстрации, на странице приложения, я размещу прямоугольник, который можно будет таскать при помощи мыши. Когда приложение перезапускается, положение у прямоугольника должно быть такое, какое оставил пользователь в прошлый раз.
XAML главной страницы будет иметь вид:
Grid>
Соответственно, в коде введем дополнительное поле и обработчик для события ManipulationDelta:
{
if (dragTranslation == null)
{
dragTranslation = new TranslateTransform();
movedRectangle.RenderTransform = dragTranslation;
}
dragTranslation.X += e.Delta.Translation.X;
dragTranslation.Y += e.Delta.Translation.Y;
}
Теперь, при запуске приложения, в центре экрана будет появляться красный прямоугольник, который мы можем таскать мышкой (кстати, забавный эффект, если схватить, резко дернуть в сторону и отпустить, прямоугольник вылетает за пределы экрана):
Нам, теперь необходимо реализовать загрузку положения прямоугольника при старте приложения и сохранение настроек, при переходе приложения в режим ожидания. Добавим загрузку параметров в конструктор главного окна и подпишемся на событие перехода в режим ожидания:
this.InitializeComponent();
// Получаем локальные настройки приложения
ApplicationDataContainer localSettings = ApplicationData.Current.LocalSettings;
// Пытаемся прочитать предыдущее положение прямоугольника
if (localSettings.Values["x"] != null && localSettings.Values["y"] != null)
{
dragTranslation = new TranslateTransform();
movedRectangle.RenderTransform = dragTranslation;
dragTranslation.X += double.Parse(localSettings.Values["x"].ToString());
dragTranslation.Y += double.Parse(localSettings.Values["y"].ToString());
}
}
void Current_Suspending(object sender, Windows.ApplicationModel.SuspendingEventArgs e)
{
// Сохраняем настройки
if (dragTranslation != null)
{
ApplicationDataContainer localSettings = ApplicationData.Current.LocalSettings;
localSettings.Values["x"] = dragTranslation.X;
localSettings.Values["y"] = dragTranslation.Y;
}
}
Едиственно, чтобы проверить как это работает, мне пришлось компьютер отправить в спящий режим, т.к. иначе событие Suspending для приложения не вызывалось. Но после включения, прямоугольник остался на том месте в котором я его оставил (причем при запуске из Visual Studio в режиме debug я убедился, что значения считываются правильно).
Если обратили внимание, то я использую вот такую жуткую конструкцию: double.Parse(localSettings.Values["x"].ToString());. На самом деле, в Values хранится тот тип простого параметра который я туда записал. И можно воспользоваться приведением типов, для того чтобы его получить. Но что делать, если мне надо хранить не простые значения, а составные? Например, не просто x и y, а их пару? Смотрим второй пример.
Второй пример, на хранение комплексных типов. Я буду решать туже задачу, только сохранять буду комплексный тип (содержащий x и y), ну и не буду использовать Parse. Для этого, я изменю следующим образом конструктор и методо обработчика события приостановки приложения:
this.InitializeComponent();
// Получаем локальные настройки приложения
ApplicationDataContainer localSettings = ApplicationData.Current.LocalSettings;
// Пытаемся прочитать предыдущее положение прямоугольника
if (localSettings.Containers.ContainsKey("point"))
{
ApplicationDataContainer point = localSettings.Containers["point"];
dragTranslation = new TranslateTransform();
movedRectangle.RenderTransform = dragTranslation;
dragTranslation.X += (double)point.Values["x"];
dragTranslation.Y += (double)point.Values["y"];
}
// Подписываемся на событие перехода приложением в режим ожидания
Application.Current.Suspending += Current_Suspending;
}
void Current_Suspending(object sender, Windows.ApplicationModel.SuspendingEventArgs e)
{
// Сохраняем настройки
if (dragTranslation != null)
{
ApplicationDataContainer localSettings = ApplicationData.Current.LocalSettings;
localSettings.CreateContainer("point", Windows.Storage.ApplicationDataCreateDisposition.Always);
localSettings.Containers["point"].Values["x"] = dragTranslation.X;
localSettings.Containers["point"].Values["y"] = dragTranslation.Y;
}
}
Кстати, сохранение параметров можно записать и вот так:
// Сохраняем настройки
if (dragTranslation != null)
{
ApplicationDataContainer localSettings = ApplicationData.Current.LocalSettings;
ApplicationDataContainer point = localSettings.CreateContainer("point", Windows.Storage.ApplicationDataCreateDisposition.Always);
point.Values["x"] = dragTranslation.X;
point.Values["y"] = dragTranslation.Y;
}
}
Ну и в третьем примере, давайте перейдем к хранению настроек в облаке. Изменения по сравнению с предыдущим примером минимальны. Вместо LocalSettings необходимо использовать RoamingSettings:
ApplicationDataContainer roamingSettings = ApplicationData.Current.RoamingSettings;
// Пытаемся прочитать предыдущее положение прямоугольника
if (roamingSettings.Containers.ContainsKey("point"))
{
ApplicationDataContainer point = roamingSettings.Containers["point"];
dragTranslation = new TranslateTransform();
movedRectangle.RenderTransform = dragTranslation;
dragTranslation.X += (double)point.Values["x"];
dragTranslation.Y += (double)point.Values["y"];
}
// Подписываемся на событие перехода приложением в режим ожидания
Application.Current.Suspending += Current_Suspending;
}
void Current_Suspending(object sender, Windows.ApplicationModel.SuspendingEventArgs e)
{
// Сохраняем настройки
if (dragTranslation != null)
{
ApplicationDataContainer roamingSettings = ApplicationData.Current.RoamingSettings;
ApplicationDataContainer point = roamingSettings.CreateContainer("point", Windows.Storage.ApplicationDataCreateDisposition.Always);
point.Values["x"] = dragTranslation.X;
point.Values["y"] = dragTranslation.Y;
}
}
Ну и последний четвертый пример, на отслеживание изменения настроек в облаке. Для этого, подпишемся на соответствующее событие и попробуем сохранять данные на каждое изменение и читать, соответственно также на каждое изменение:
this.InitializeComponent();
// Подписываемся на изменение данных
ApplicationData.Current.DataChanged += Current_DataChanged;
...
}
void Current_DataChanged(ApplicationData sender, object args)
{
// Перечитываем настройки
ApplicationDataContainer roamingSettings = ApplicationData.Current.RoamingSettings;
// Пытаемся прочитать положение прямоугольника
if (roamingSettings.Containers.ContainsKey("point") && dragTranslation != null)
{
ApplicationDataContainer point = roamingSettings.Containers["point"];
dragTranslation.X += (double)point.Values["x"];
dragTranslation.Y += (double)point.Values["y"];
}
}
private void Rectangle_ManipulationDelta_1(object sender, ManipulationDeltaRoutedEventArgs e)
{
if (dragTranslation == null)
{
dragTranslation = new TranslateTransform();
movedRectangle.RenderTransform = dragTranslation;
}
dragTranslation.X += e.Delta.Translation.X;
dragTranslation.Y += e.Delta.Translation.Y;
ApplicationDataContainer roamingSettings = ApplicationData.Current.RoamingSettings;
ApplicationDataContainer point = roamingSettings.CreateContainer("point", Windows.Storage.ApplicationDataCreateDisposition.Always);
point.Values["x"] = dragTranslation.X;
point.Values["y"] = dragTranslation.Y;
}
Теперь, если запустить приложение на двух устройствах с Windows 8, то при перетаскивании прямоугольника на одном, он должен сам перетаскиваться на другом.
P.s. Т.к. у меня нет двух устройств с Windows 8 на борту, то если у кого есть и он попробует последний пример, отпишитесь, очень интересно...
Итак, в Metro Style приложениях вы можете хранить настройки программы как локально на устройстве (например позиционирование элементов под конкретное разрешение), так и в облаке, в этом случае доступ будет со всех устройств пользователя (например можно хранить рекорд пользователя).
В рамках первого примера, рассмотрим сохранение одиночных значений в локальном хранилище. Для демонстрации, на странице приложения, я размещу прямоугольник, который можно будет таскать при помощи мыши. Когда приложение перезапускается, положение у прямоугольника должно быть такое, какое оставил пользователь в прошлый раз.
XAML главной страницы будет иметь вид:
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<Rectangle x:Name="movedRectangle"
Width="100" Height="50" Fill="Red" ManipulationMode="All" ManipulationDelta="Rectangle_ManipulationDelta_1"
/>Grid>
Соответственно, в коде введем дополнительное поле и обработчик для события ManipulationDelta:
private TranslateTransform dragTranslation;
private void Rectangle_ManipulationDelta_1(object sender, ManipulationDeltaRoutedEventArgs e){
if (dragTranslation == null)
{
dragTranslation = new TranslateTransform();
movedRectangle.RenderTransform = dragTranslation;
}
dragTranslation.X += e.Delta.Translation.X;
dragTranslation.Y += e.Delta.Translation.Y;
}
Теперь, при запуске приложения, в центре экрана будет появляться красный прямоугольник, который мы можем таскать мышкой (кстати, забавный эффект, если схватить, резко дернуть в сторону и отпустить, прямоугольник вылетает за пределы экрана):
Нам, теперь необходимо реализовать загрузку положения прямоугольника при старте приложения и сохранение настроек, при переходе приложения в режим ожидания. Добавим загрузку параметров в конструктор главного окна и подпишемся на событие перехода в режим ожидания:
public MainPage()
{this.InitializeComponent();
// Получаем локальные настройки приложения
ApplicationDataContainer localSettings = ApplicationData.Current.LocalSettings;
// Пытаемся прочитать предыдущее положение прямоугольника
if (localSettings.Values["x"] != null && localSettings.Values["y"] != null)
{
dragTranslation = new TranslateTransform();
movedRectangle.RenderTransform = dragTranslation;
dragTranslation.X += double.Parse(localSettings.Values["x"].ToString());
dragTranslation.Y += double.Parse(localSettings.Values["y"].ToString());
}
// Подписываемся
на событие перехода приложением в режим ожидания
Application.Current.Suspending
+= Current_Suspending;}
void Current_Suspending(object sender, Windows.ApplicationModel.SuspendingEventArgs e)
{
// Сохраняем настройки
if (dragTranslation != null)
{
ApplicationDataContainer localSettings = ApplicationData.Current.LocalSettings;
localSettings.Values["x"] = dragTranslation.X;
localSettings.Values["y"] = dragTranslation.Y;
}
}
Едиственно, чтобы проверить как это работает, мне пришлось компьютер отправить в спящий режим, т.к. иначе событие Suspending для приложения не вызывалось. Но после включения, прямоугольник остался на том месте в котором я его оставил (причем при запуске из Visual Studio в режиме debug я убедился, что значения считываются правильно).
Если обратили внимание, то я использую вот такую жуткую конструкцию: double.Parse(localSettings.Values["x"].ToString());. На самом деле, в Values хранится тот тип простого параметра который я туда записал. И можно воспользоваться приведением типов, для того чтобы его получить. Но что делать, если мне надо хранить не простые значения, а составные? Например, не просто x и y, а их пару? Смотрим второй пример.
Второй пример, на хранение комплексных типов. Я буду решать туже задачу, только сохранять буду комплексный тип (содержащий x и y), ну и не буду использовать Parse. Для этого, я изменю следующим образом конструктор и методо обработчика события приостановки приложения:
public MainPage()
{this.InitializeComponent();
// Получаем локальные настройки приложения
ApplicationDataContainer localSettings = ApplicationData.Current.LocalSettings;
// Пытаемся прочитать предыдущее положение прямоугольника
if (localSettings.Containers.ContainsKey("point"))
{
ApplicationDataContainer point = localSettings.Containers["point"];
dragTranslation = new TranslateTransform();
movedRectangle.RenderTransform = dragTranslation;
dragTranslation.X += (double)point.Values["x"];
dragTranslation.Y += (double)point.Values["y"];
}
// Подписываемся на событие перехода приложением в режим ожидания
Application.Current.Suspending += Current_Suspending;
}
void Current_Suspending(object sender, Windows.ApplicationModel.SuspendingEventArgs e)
{
// Сохраняем настройки
if (dragTranslation != null)
{
ApplicationDataContainer localSettings = ApplicationData.Current.LocalSettings;
localSettings.CreateContainer("point", Windows.Storage.ApplicationDataCreateDisposition.Always);
localSettings.Containers["point"].Values["x"] = dragTranslation.X;
localSettings.Containers["point"].Values["y"] = dragTranslation.Y;
}
}
Кстати, сохранение параметров можно записать и вот так:
void Current_Suspending(object sender, Windows.ApplicationModel.SuspendingEventArgs e)
{// Сохраняем настройки
if (dragTranslation != null)
{
ApplicationDataContainer localSettings = ApplicationData.Current.LocalSettings;
ApplicationDataContainer point = localSettings.CreateContainer("point", Windows.Storage.ApplicationDataCreateDisposition.Always);
point.Values["x"] = dragTranslation.X;
point.Values["y"] = dragTranslation.Y;
}
}
Ну и в третьем примере, давайте перейдем к хранению настроек в облаке. Изменения по сравнению с предыдущим примером минимальны. Вместо LocalSettings необходимо использовать RoamingSettings:
public MainPage()
{
this.InitializeComponent();
// Получаем
глобальные настройки приложенияApplicationDataContainer roamingSettings = ApplicationData.Current.RoamingSettings;
// Пытаемся прочитать предыдущее положение прямоугольника
if (roamingSettings.Containers.ContainsKey("point"))
{
ApplicationDataContainer point = roamingSettings.Containers["point"];
dragTranslation = new TranslateTransform();
movedRectangle.RenderTransform = dragTranslation;
dragTranslation.X += (double)point.Values["x"];
dragTranslation.Y += (double)point.Values["y"];
}
// Подписываемся на событие перехода приложением в режим ожидания
Application.Current.Suspending += Current_Suspending;
}
void Current_Suspending(object sender, Windows.ApplicationModel.SuspendingEventArgs e)
{
// Сохраняем настройки
if (dragTranslation != null)
{
ApplicationDataContainer roamingSettings = ApplicationData.Current.RoamingSettings;
ApplicationDataContainer point = roamingSettings.CreateContainer("point", Windows.Storage.ApplicationDataCreateDisposition.Always);
point.Values["x"] = dragTranslation.X;
point.Values["y"] = dragTranslation.Y;
}
}
Ну и последний четвертый пример, на отслеживание изменения настроек в облаке. Для этого, подпишемся на соответствующее событие и попробуем сохранять данные на каждое изменение и читать, соответственно также на каждое изменение:
public MainPage()
{this.InitializeComponent();
// Подписываемся на изменение данных
ApplicationData.Current.DataChanged += Current_DataChanged;
...
}
void Current_DataChanged(ApplicationData sender, object args)
{
// Перечитываем настройки
ApplicationDataContainer roamingSettings = ApplicationData.Current.RoamingSettings;
// Пытаемся прочитать положение прямоугольника
if (roamingSettings.Containers.ContainsKey("point") && dragTranslation != null)
{
ApplicationDataContainer point = roamingSettings.Containers["point"];
dragTranslation.X += (double)point.Values["x"];
dragTranslation.Y += (double)point.Values["y"];
}
}
private void Rectangle_ManipulationDelta_1(object sender, ManipulationDeltaRoutedEventArgs e)
{
if (dragTranslation == null)
{
dragTranslation = new TranslateTransform();
movedRectangle.RenderTransform = dragTranslation;
}
dragTranslation.X += e.Delta.Translation.X;
dragTranslation.Y += e.Delta.Translation.Y;
ApplicationDataContainer roamingSettings = ApplicationData.Current.RoamingSettings;
ApplicationDataContainer point = roamingSettings.CreateContainer("point", Windows.Storage.ApplicationDataCreateDisposition.Always);
point.Values["x"] = dragTranslation.X;
point.Values["y"] = dragTranslation.Y;
}
Теперь, если запустить приложение на двух устройствах с Windows 8, то при перетаскивании прямоугольника на одном, он должен сам перетаскиваться на другом.
P.s. Т.к. у меня нет двух устройств с Windows 8 на борту, то если у кого есть и он попробует последний пример, отпишитесь, очень интересно...
прямоугольник вылетает за пределы экрана << уже заложена кинетическая прокрутка?
ОтветитьУдалитьИ ещё - объём в облаке ограничивают? Завязка только с серверами MS или можно и свой организовать?
* ищет шапочку из фольги :D
Да, ограничивают. Сейчас бесплатно 7 ГБ (310 руб/год стоит 20 ГБ, за 1570 руб/год - 100 ГБ). Из приложения квоту можно посмотреть через ApplicationData.RoamingStorageQuota (возвращает в КБ). Других хранилищ кроме MS насколько я знаю подключить нельзя.
ОтветитьУдалить