Главная » WPF » Передача состояния между страницами WPF

0

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

Для следующего примера  напишем  две страницы:  первая  будет запрашивать имя пользователя, а вторая – выводить ему приветствие.  На первой странице по# местим текстовое  поле для ввода данных и ссылку для перехода на следующую страницу:

<Page … x:Class=’EssentialWPF.Name’ WindowTitle=’Who are you?’

<StackPanel>

<Label>What is your name?</Label>

<TextBox Name=’_nameBox’/>

<TextBlock>

<Hyperlink NavigateUri=’hello.xaml’>Continue</Hyperlink>

</TextBlock>

</StackPanel>

</Page>

На  сторой  странице  будет только  метка, в которой  отображается введен#

ное имя:

<Page … x:Class=’EssentialWPF.Hello’ WindowTitle=’Hello!’

<StackPanel>

<TextBlock>Hello!</TextBlock>

<Label Name=’_name’ />

</StackPanel>

</Page>

Первый  шаг – скопировать данные из текстового  поля на страницу  с именем и заставить  приложение показать  эту страницу.  Затем  можно  модифицировать логику навигации,  добавив сохранение  необходимых  данных. Подписавшись на событие RequestNavigate, мы сможем сохранить имя в объекте Application  непос# редственно перед тем, как произойдет  переход (рис. 2.19):

Рис. 2.19. Ввод данных на странице name.xaml

<!— name.xaml —>

<Page … x:Class=’EssentialWPF.Name’ WindowTitle=’Who are you?’

<StackPanel>

<Hyperlink NavigateUri=’hello.xaml’ RequestNavigate=’Page_RequestNavigate’

Continue

</Hyperlink>

</StackPanel>

</Page>

// name.xaml.cs

public partial class Name : Page {

void Page_RequestNavigate(object sender, RequestNavigateEventArgs e) {

Application.Current.Properties[«Name»] = _nameBox.Text;

}

}

Рис. 2.20. Получение данных от страницы name.xaml

На второй странице необходимо подписаться на событие Loaded, извлечь данные из объекта Application  и вывести их (рис. 2.20):

<!— hello.xaml —>

<Page … x:Class=»EssentialWPF.Hello» Text=»Hello!» Loaded=»PageLoaded»

</Page>

// hello.xaml.cs using System;

using System.Windows;

using System.Windows.Navigation;

using System.Windows.Controls;

namespace EssentialWPF {

public partial class Hello : Page {

public Hello() { InitializeComponent();

}

void PageLoaded(object sender, EventArgs e) {

_name.Content = Application.Current.Properties[«Name»];

}

}

}

Такой подход прекрасно  работает в простых сценариях,  но вообще#то исполь# зование объекта Application подобным образом ничем не отличается от использо# вания глобальной  переменной.  Вся моя объектно#ориентированная природа воз# мущается,  когда я вижу код с глобальными переменными. Напомню,  что мы не обязаны  выполнять навигацию  только  с помощью  URI;  можно  создать  вторую страницу  программно  и задать для нее свойства,  как для любого объекта. Тогда обмен данными между двумя страницами удастся инкапсулировать:

<!— hello.xaml —>

<Page … x:Class=’EssentialWPF.Hello’ Text=’Hello!’

</Page>

// hello.xaml.cs

public partial class Hello : Page {

public string Name {

set { _name.Content = value; }

}

}

<!— name.xaml —>

<Page …>

<Hyperlink Click=’Navigate’>Continue</Hyperlink>

</Page>

// name.xaml.cs

void Navigate(object sender, RoutedEventArgs e) { Hello hello = new Hello();

hello.Name = _nameBox.Text; NavigationService.Navigate(hello);

}

Многообещающий способ передачи состояния между страницами – аргумент navigationState метода Navigate:

public class NavigationService {

public bool Navigate(object root);

public bool Navigate(Uri source);

public bool Navigate(object root, object navigationState);

public bool Navigate(Uri source, object navigationState);

}

Хотя догадаться об этом довольно сложно, мы можем запомнить данные в обработ# чике события LoadCompleted объекта NavigationService. Сначала изменим вызываю# щую программу так, чтобы она передавала дополнительные данные при вызове Navigate:

void Navigate(object sender, RoutedEventArgs e) { Hello hello = new Hello(); NavigationService.Navigate(hello, _nameBox.Text);

}

На второй странице  подпишемся на событие LoadCompleted. Свойство  стра# ницы NavigationService равно null, пока не произойдет  событие Loaded, поэтому мы должны подписаться на событие LoadCompleted17  в обработчике  события Loaded (я же сказал, что догадаться нелегко):

void PageLoaded(object sender, EventArgs e) {

NavigationService.LoadCompleted += LoadCompleted;

}

void LoadCompleted(object sender, NavigationEventArgs e) {

_name.Content = e.ExtraData; NavigationService.LoadCompleted — = LoadCompleted;

}

Существует много способов подписаться на событие LoadCompleted, и у каждого есть свои плюсы и минусы. Использование объекта Application означает наличие некоего гло# бального состояния, с которым трудно работать в крупных приложениях. Задание свойств отдельных страниц лишает нас возможности декларативно описывать навигацию на язы# ке XAML. У аргумента navigationState метода Navigate такая же проблема.

Мне кажется, что для страниц с параметрами лучше всего создать команду нави# гации (поскольку команды могут иметь параметры) и стилизовать кнопку (которая поддерживает команды)  под гиперссылку18. Не особенно элегантно, но работает.

17  Отметим также, что в том же обработчике необходимо отказаться от подписки на событие LoadCompleted. Дело в том, что LoadCompleted — событие объекта NavigationService, поэтому оно будет возникать для каждой страницы, загружаемой в NavigationService. Отказываясь от подписки после получения извещения от загружаемой страницы, мы избегаем получения лишних извещений. Кроме того, отказ от подписки важен и для того, чтобы объект NavigationService не держал нашу страницу в памяти в течение всего времени жизни службы.

18 Пример см. на странице http://blog.simplegeek.com/book.

Источник: К. Андерсон  Основы  Windows Presentation Foundation. Пер. с англ. А. Слинкина — М.: ДМК Пресс, 2008 — 432 с.: ил.

По теме:

  • Комментарии