Главная » WPF » Функциональная навигация и страничные функции

0

В наши дни традиционная навигация не структурирована. Это как програм# мирование  на языке BASIC  в 1960#е годы – использование goto для произволь# ных переходов  между разными  частями  программами, глобальных  переменных для отслеживания состояния и необходимость изменять номера строк при любой модификации. Сегодня мы говорим о гиперссылках, состоянии сеанса и URI, но суть проблемы остается той же. Работу Web#сайта легко нарушить, поток управ# ления в нем изменяется с трудом, а для инкапсуляции функциональности прихо# дится затрачивать несоразмерные усилия.

Рис. 2.23. Первая страничная функция: вывод строки «Welcome!»

Класс PageFunction является производным от Page, поэтому всюду, где возмож# на навигация к Page, возможна  и навигация к PageFunction. Чтобы вывести стра# ницу приветствия, необходимо создать окно навигации и перейти в него (рис. 2.23):

public class Program { [STAThread]

static void Main() {

Application app = new Application(); NavigationWindow w = new NavigationWindow(); w.Show();

w.Navigate(new Welcome());

app.Run();

}

}

В консольной  программе за выводом приветствия следовало обращение к ме# тоду SayHello. Инкапсуляция логики – важное достоинство функциональной мо# дели программирования, поэтому мы не хотим, чтобы страница приветствия зна# ла о том, как реализован метод SayHello. Далее нужно сделать еще две вещи: соз# дать новый производный от PageFunction класс для реализации SayHello  и орга# низовать  связь между страницами Welcome и SayHello:

public class Welcome : PageFunction<object> {

public Welcome() {

TextBlock block = new TextBlocks();

block.FontSize=24; block.Inlines.Add(«Welcome!»); Hyperlink link = new Hyperlink(); link.Inlines.Add(«Next»); link.Click += DoSayHello; block.Inlines.Add(link);

Content = block;

}

void DoSayHello(object sender, RoutedEventArgs e) { NavigationService.Navigate(new SayHello());

}

}

public class SayHello : PageFunction<object> {

public SayHello() {

}

}

Вызов нашего первого метода завершен. До сих пор модель ничем не отличалась от традиционной навигации:  в отчет на щелчок мышью происходит  переход к следую# щей странице. А вот метод GetName более интересен; у него есть возвращаемое значе# ние. Мы знаем, что SayHello должен получить имя пользователя. Однако на страницу SayHello  мы уже перешли. У вызова PageFunction с возвращаемым значением  есть два важных аспекта. Во#первых, в силу асинхронной природы навигации завершение функции моделируется событием. Мы подписываемся на событие GetName.Return, чтобы выполнить те или иные действия после завершения функции. Это может пока# заться  очевидным, но немного подумав, вы поймете, что страницу  SayHello  следует выгрузить  для того, чтобы отобразилась страница  GetName.  Для реализации такого поведения можно воспользоваться свойством KeepAlive, которое позволяет удержать SayHello в памяти так, чтобы по завершении GetName был активирован тот же самый экземпляр SayHello. Свойство KeepAlive применимо к любой странице.

На рис. 2.24 изображен поток навигации. Сначала создается объект Welcome, а за# тем мы переходим к SayHello. В этот момент объект Welcome уничтожается. Первое, что делает SayHello, – это переход к GetName, но, поскольку  KeepAlive равно true, в журнале сохраняется экземпляр SayHello (а не просто URI, которые обычно записы# вается в журнал). После возврата из GetName страницы SayHello отображается снова.

Для  программной  реализации описанного  потока  навигации модифицируем SayHello,  так чтобы вызывалась  страница  GetName.  Обращаться к NavigationService.Navigate можно только после инициализации объекта; во время работы конструктора никакого объекта NavigationService еще не существует:

public class SayHello : PageFunction<object> {

public SayHello() {

// Необходимо остаться в памяти, чтобы можно было отреагировать

// на возврат из GetName

//

this.KeepAlive = true;

// После инициализации этой страницы мы сначала должны получить

// имя пользователя

//

this.Initialized += DoGetName;

}

void DoGetName(object sender, EventArgs e) {

// Чтобы получить имя пользователя, мы переходим к

// GetName и ожидаем ее завершения (события Return)

//

GetName get = new GetName(); get.Return += GetNameReturned; NavigationService.Navigate(get);

}

void GetNameReturned(object sender, ReturnEventArgs<string> e) {

// Когда GetName вернет управление, мы сможем обновить

// содержимое страницы – поприветствовать пользователя

//

Label label = new Label();

label.Content = string.Format(«Hello {0}», e2.Result); Content = label;

}

}

Осталось еще реализовать страницу GetName. Так как GetName возвращает строку, определим ее как класс, производный от PageFunction<string>. Добавим метку для вы# вода описания, текстовое поле, в которое пользователь сможет ввести имя, и кнопку за# вершения. Если вызывать метод OnReturn, то инфраструктура страничных функций ав# томатически возбудит событие Return и выполнит переход на вызвавшую страницу:

public class GetName : PageFunction<string> {

public GetName() {

StackPanel stack = new StackPanel(); Label label = new Label(); label.Content = «What is your name?»; stack.Children.Add(label);

TextBox nameBox = new TextBox();

stack.Children.Add(nameBox);

Button done = new Button(); done.Content = «Done»; done.Click += ReturnName; stack.Children.Add(done); Content = stack;

}

void ReturnName(object sender, RoutedEventArgs e) { OnReturn(new ReturnEventArgs<string>(nameBox.Text));

}

}

Отметим, что в реализации GetName вообще не упоминается SayHello. GetName ведет себя как функция в языке программирования, ее можно вызывать откуда угодно, и она всегда будет выполнять возврат на нужную страницу.

Страничные функции – это, безусловно,  важнейшая инновация, появившаяся в WPF. Раз мы стали думать о вызовах методов как о навигации,  а результаты  возвра# щать в виде событий, то можно применить к созданию приложений со средствами на# вигации модели, характерные для написания объектно#ориентированного кода. Иног# да простых ссылок на страницы достаточно, но для решения многих задач использо# вание функционально#ориентированной модели навигации намного продуктивнее.

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

По теме:

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