День #6. Общие данные, передача данных в приложении

Posted on Ноябрь 19, 2010

2


Добрый вечер!

Это 6 статья из цикла Windows Phone 7 для начинающих. Вчера мы с вами говорили о навигации, хоть я и обещал поговорить про «Application Bar», мы этого не будем делать. сегодняшнее занятие будет полностью базироваться на вчерашнем, так что советую вам прочитать его тут. Мы будем использовать то же приложение с навигацией. Немного поболтав с несколькими студентами я выяснил что они даже не представляют себе как же правильно передавать данные между страницами или делать что-то общим для всего приложения.

Что же, прыгаем с места в карьер:

Давайте возьмем наше вчерашнее приложение и попробуем сделать так, что бы когда мы переходим с первой страницы на вторую, передавать цвет первой страницы. Смотрим на код MainPage.xaml.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;

namespace day_6_working_with_data
{
	public partial class MainPage : PhoneApplicationPage
	{
		Random rand = new Random();
		// Constructor
		public MainPage()
		{
			InitializeComponent();
		}

		private void TextBlock_ManipulationStarted(object sender, ManipulationStartedEventArgs args)
		{
			string destination = "/SecondPage.xaml";
			if (ContentPanel.Background is SolidColorBrush)
			{
				Color clr = (ContentPanel.Background as SolidColorBrush).Color;
				destination += String.Format("?Red={0}&Green={1}&Blue={2}",
				clr.R, clr.G, clr.B);
			}
			this.NavigationService.Navigate(new Uri(destination, UriKind.Relative));
			args.Complete();
			args.Handled = true;
		}

		protected override void OnManipulationStarted(ManipulationStartedEventArgs args)
		{
			ContentPanel.Background = new SolidColorBrush(
				Color.FromArgb(255, (byte) rand.Next(255),
				               (byte) rand.Next(255),
				               (byte) rand.Next(255)));
			base.OnManipulationStarted(args);

		}
	}
}

Следует заметить что изменился только метод, который отвечает за действия пользователя с Текстблоком. Если вы знакомы с основами HTML, то вы сразу заметите что мы формируем обычную ссылку, которая будет содержать несколько параметров. Она будет выглядеть как-то так:

“/SecondPage.xaml?Red=223&Green=143&Blue=146”

Теперь перейдем к коду второй страницы:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;

namespace day_6_working_with_data
{
	public partial class SecondPage : PhoneApplicationPage
	{
		Random rand = new Random();
		public SecondPage()
		{
			InitializeComponent();
		}

		private void TextBlock_ManipulationStarted(object sender, ManipulationStartedEventArgs args)
		{
			this.NavigationService.GoBack();
			args.Complete();
			args.Handled = true;
		}

		protected override void OnManipulationStarted(ManipulationStartedEventArgs args)
		{
			ContentPanel.Background = new SolidColorBrush(
				Color.FromArgb(255, (byte)rand.Next(255),
							   (byte)rand.Next(255),
							   (byte)rand.Next(255)));
			base.OnManipulationStarted(args);
		}

		protected override void OnNavigatedTo(NavigationEventArgs args)
		{
			IDictionary<string, string> parameters = this.NavigationContext.QueryString;
			if (parameters.ContainsKey("Red"))
			{
				byte R = Byte.Parse(parameters["Red"]);
				byte G = Byte.Parse(parameters["Green"]);
				byte B = Byte.Parse(parameters["Blue"]);
				ContentPanel.Background =
					new SolidColorBrush(Color.FromArgb(255, R, G, B));
			}
			base.OnNavigatedTo(args);
		}
	}
}

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

Мы используем свойство NavigationContext, которое называется QueryString, которое, в свою очередь, является словарем. В коде мы проверяем наличие параметра «Red», подразумевая при этом, что «Blue» и «Green» будут присутствовать. Далее перегоняем данные в Byte и создаем на основе них цвет, которым и красим фон.

Теперь при переходе с Главной страницы на вторую цвет фона будет оставаться, но если вы измените цвет на второй странице и вернетесь на первую, то там ничего не изменится.

Общие данные

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

Перейдем к  файлу App.xaml.cs и в его начало добавим

	public partial class App : Application
	{
		/// <summary>
		/// Общее свойство цвета для наших страниц
		/// </summary>
		public Color? SharedColor { set; get; }

Теперь подредактируем код на MainPage.xaml.cs исправив механизм хранения текущего цвета

		private void TextBlock_ManipulationStarted(object sender, ManipulationStartedEventArgs args)
		{
			if (ContentPanel.Background is SolidColorBrush) (Application.Current as App).SharedColor = (ContentPanel.Background as SolidColorBrush).Color;
			this.NavigationService.Navigate(new Uri("/SecondPage.xaml", UriKind.Relative));
			args.Complete();
			args.Handled = true;
		}

А на SecondPage.xaml.cs подправим метод OnNavigatedTo

	    protected override void OnNavigatedTo(NavigationEventArgs args)
		{
			Color? sharedColor = (Application.Current as App).SharedColor;
			if (sharedColor != null)
				ContentPanel.Background =
				new SolidColorBrush(sharedColor.Value);
			base.OnNavigatedTo(args);
		}

Тоже самое сделаем и в обратном случае, .т.е. добавим сохранение цвета TextBlock_ManipulationStarted на SecondPage.xaml.cs и добавим метод OnNavigatedTo на MainPage.xaml.cs.

Теперь при переходе между страницами у нас постоянно сохраняется цвет, даже при изменении его на второй странице.

Кроме метода OnNavigatedTo у страницы так же есть метод OnNavigatedFrom method, который сначала покажется намного менее полезным. Страница же знает что осуществляет навигацию с самой себя, т.к. только что вызвала метод Navigate или GoBack 🙂

Рассмотрим такую ситуацию:  Главная страница вызывает метод Navigate с аргументами “/SecondPage.xaml”. Метод OnNavigatedFrom на Главной странице вызывается с аргументами, свойством которых является Uri содержащая “/SecondPage.xaml”, а в свойстве Content тип SecondPage. Это свежесозданная сущность SecondPage котрая вскоре будет отображена и это самый простой путь получить доступ к этой сущности.

Это же происходит и когда мы возвращаемся со второй страницы. Получается, что еще до показа страницы, у нас она уже есть! Т.е. мы можем задать какое-то свойство или вызвать один из методов!

Посмотрим на примере:

Немного изменим код MainPage.xaml.cs, добавив новое свойство и немного изменив метод OnNavigatedTo что бы он брал значение из нового поля

     		public Color? ReturnedColor { set; get; }
		protected override void OnNavigatedTo(NavigationEventArgs args)
		{
			if (ReturnedColor != null)
				ContentPanel.Background = new SolidColorBrush(ReturnedColor.Value);
			base.OnNavigatedTo(args);
		}

Теперь посмотрим как же задать это свойство с другой страницы:

Добавим метод OnNavigatedFrom на SecondPage.xaml.cs

		protected override void OnNavigatedFrom(NavigationEventArgs args)
		{
			if (ContentPanel.Background is SolidColorBrush)
			{
				Color clr = (ContentPanel.Background as SolidColorBrush).Color;
				if (args.Content is MainPage)
					(args.Content as MainPage).ReturnedColor = clr;
			}
			base.OnNavigatedFrom(args);
		}

Мы приводим аргументы метода к типу Главной страницы задаем одно из ее свойств. Что может быть проще?!

В итоге, мы общаемся со страницей как с диалоговым окном. Получается что мы выбираем текст первой страницы на второй. Запустите приложение и сами посмотрите, цвет второй страницы всегда будет черным (или белым, если светлая тема), а вот после перемены цвета и возврата на главную, у нее будет цвет который мы выбрали в «диалоговом окне».

Данные между сущностями

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

Если мы хотим чтобы вторая  страница «помнила» последний цвет, нам необходимо что-то снаружи второй страницы для сохранения данных. Как вариант, это может быть вторая страница или IsolatedStorage (мы позже еще поговорим о нем). Третьим и правильным решением является решение предоставленное нам классом PhoneApplicationService, определенном в Microsoft.Phone.Shell. Экземпляр PhoneApplicationService создается в стандартном App.xaml:

<Application.ApplicationLifetimeObjects>
<!--Required object that handles lifetime events for the application-->
    <shell:PhoneApplicationService
        Launching="Application_Launching" Closing="Application_Closing"
        Activated="Application_Activated" Deactivated="Application_Deactivated"/>
</Application.ApplicationLifetimeObjects>

Не надо создавать новый PhoneApplicationService. можно получить доступ к существующему с помощью статического свойства PhoneApplicationService.Current.

PhoneApplicationService содержит свойство State, которое является словарем и позволяет нам сохранять и читать данные. Свойство State типа IDictionary<string, object>. Следовательно с помощью строковых ключей мы можем хранить данные. Но важно знать, что эти данные хранятся только пока приложение работает. Их нельзя использовать для разных запусков того же приложения.

Все что вы захотите сохранить в этом словаре должно уметь сериализироваться (должна быть возможность сделать из объекта XML). Так же должен быть публичный конструктор без параметров. И все публичные свойства тоже должны уметь сериализироваться.

Немного модифицируем нашу программу:
Вот текст SecondPage.xaml.cs

using System;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Navigation;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Shell;

namespace day_6_working_with_data
{
	public partial class SecondPage : PhoneApplicationPage
	{
		Random rand = new Random();
		public SecondPage()
		{
			InitializeComponent();
		}

		private void TextBlock_ManipulationStarted(object sender, ManipulationStartedEventArgs args)
		{
			this.NavigationService.GoBack();
			args.Complete();
			args.Handled = true;
		}
		protected override void OnManipulationStarted(ManipulationStartedEventArgs args)
		{
			ContentPanel.Background = new SolidColorBrush(
				Color.FromArgb(255, (byte)rand.Next(255),
							   (byte)rand.Next(255),
							   (byte)rand.Next(255)));
			base.OnManipulationStarted(args);
		}
		protected override void OnNavigatedFrom(NavigationEventArgs args)
		{
			if (ContentPanel.Background is SolidColorBrush)
			{
				Color clr = (ContentPanel.Background as SolidColorBrush).Color;
				if (args.Content is MainPage)
					(args.Content as MainPage).ReturnedColor = clr;
				// Save color
				PhoneApplicationService.Current.State["Color"] = clr;
			}
			base.OnNavigatedFrom(args);
		}
		protected override void OnNavigatedTo(NavigationEventArgs args)
		{
			// Retrieve color
			if (PhoneApplicationService.Current.State.ContainsKey("Color"))
			{
				Color clr = (Color)PhoneApplicationService.Current.State["Color"]; ContentPanel.Background = new SolidColorBrush(clr);
			}
			base.OnNavigatedTo(args);
		}
	}
}

Во время выполнения OnNavigatedFrom, если у нас есть правильный цвет, мы сохраняем его в наш словарь с ключом “Color”:

PhoneApplicationService.Current.State[«Color»] = clr;

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

Каждый раз когда мы будем нажимать кнопку «Назад» наш словарь будет теряться. Опять же повторяю, он работает только во время работы приложения. Если вам необходимо хранить данные, например настройки для каждого запуска, воспользуйтесь IsolatedStorage.

Теперь пробуем: переходим ко второй странице. Меняем цвет нажатием на экран. Жмем Аппаратную Кнопку «Старт». Мы вышли из приложения. Можно залезть в другие программы. Но мы нажмем кнопку «Назад». Ииии! Опа, а цвет есть 🙂

Теперь возвращаемся на главную страницу, видим что цвет есть, повторяем действия уже с главной и когда возвращаемся…

Цвет пропал… Что же произошло?

Все это подводит нас к теме tombstoning. Итак завтра мы говорим о:

День #7. Некромантия. Или tombstoning в WP7.

Реклама