В моем предыдущем посте вы увидели, как перейти вперед на новую страницу и затем вернуться либо с помощью аппаратной кнопки назад, либо с помощью метода GoBack
. Довольно часто вы хотите передавать некоторые данные между страницами, например, если пользователь выбирает клиента из списка, вы можете передать идентификатор или имя клиента на страницу сведений о клиенте. В этом посте не только будет рассказано, как это сделать, но также будет освещена последовательность событий, возникающих в процессе навигации.
Для этого поста мы будем использовать простой пример приложения с двумя страницами: CustomerListPage и CustomerDetailsPage. Из CustomerListPage пользователь может выбрать клиента в списке, который вызовет переход к странице сведений. Например:
private void CustomerSelectionChanged(object sender, SelectionChangedEventArgs e) { NavigationService.Navigate(new URI("/CustomerDetailsPage.xaml", URIKind.Relative)); }
Этого недостаточно, поскольку страница сведений должна знать, какого клиента отображать. В традиционной технологии многофункционального клиента, такой как «WinForms» или «WPF», вы можете попытаться передать ссылку на объект customer на страницу сведений о клиенте. К сожалению, эта стратегия не будет работать в приложении Windows Phone, так как навигация между страницами должна быть устойчивой к захоронению приложения. Не вдаваясь в подробности обсуждения вопроса о надгробии , по сути, когда ваше приложение переходит в фоновый режим, оно, вероятно, будет захоронено, что означает, что его больше нет в памяти. Когда приложение впоследствии возобновляется, например, пользователь нажимает кнопку «Назад», чтобы вернуться к вашему приложению, на ранее созданной странице будет создана навигация, а любые объекты в памяти придется перезагрузить. Дополнительную информацию о жизненном цикле и захоронении приложений для Windows Phone можно найти в документации MSDN .
Чтобы не сталкиваться с проблемами, связанными с надгробием, вы должны рассматривать каждую страницу так, как будто она существует изолированно. Это означает, что единственный способ передать данные на страницу — через URI навигации. Поскольку URI навигации является стандартным относительным URI, он поддерживает как параметры строки запроса, так и фрагменты. Например, если вы хотите передать идентификатор клиента на страницу сведений о клиенте, вы можете воспользоваться одним из следующих:
NavigationService.Navigate(new URI("/CustomerDetailsPage.xaml?customerId=12345", URIKind.Relative)); NavigationService.Navigate(new URI("/CustomerDetailsPage.xaml#12345", URIKind.Relative));
Первый метод указывает идентификатор клиента в качестве параметра строки запроса. Это можно легко извлечь на странице назначения, изучив свойство QueryString объекта NavigationContext.
protected override void OnNavigatedTo(NavigationEventArgs e) { base.OnNavigatedTo(e); var customerId = NavigationContext.QueryString["customerId"]; }
Второй метод определяет идентификатор клиента как фрагмент URI. Этот метод несколько ограничен тем, что вы можете указать только одно значение, тогда как в строке запроса вы можете указать несколько пар ключ-значение. Однако, что хорошо в использовании фрагмента, так это то, что возникает дополнительное событие, которое позволяет странице перейти к определенному фрагменту.
protected override void OnFragmentNavigation(FragmentNavigationEventArgs e) { base.OnFragmentNavigation(e); var customerId = e.Fragment; }
На этом этапе я хотел бы немного отскочить назад и просто повторить последовательность событий, которые происходят при срабатывании навигации. Это должно помочь прояснить, где появится приведенный выше код для извлечения идентификатора клиента. Процесс навигации начинается с вызова метода Navigate
, либо непосредственно в PhoneApplicationFrame
либо в свойстве NavigationService
текущей страницы (показано в верхней части рисунка 1).

Остальная часть рисунка 1 разделена на два округлых поля: Левое поле указывает на события, которые происходят в PhoneApplicationFrame
. Вы можете дополнительно подписаться на эти события в файле App.xaml.cs
, что полезно, если вы хотите регистрировать события навигации. В большинстве случаев вас больше интересуют методы, которые вы можете переопределить на страницах вашего приложения, которые наследуются от класса PhoneApplicationPage
.
После запуска навигации первым событием, которое возникает в кадре, является событие Navigated
. И это событие, и соответствующий метод OnNavigatingFrom
, который вызывается на странице, от которой пользователь перемещается, предоставляют аргумент NavigationEventArgs
. Этот аргумент наследуется от CancelEventArgs
который предоставляет свойство Cancel
, которое может быть установлено в true, если вы хотите отменить навигацию. Это может быть полезно, если вы хотите запустить анимацию, сохранить переходное состояние или выполнить действия по очистке страницы.
На этом этапе служба навигации определяет, была ли навигация отменена. Если оно имеет событие NavigationStopped
оно генерируется в кадре. Предполагая, что навигация не была отменена, навигация продолжается. Если по какой-либо причине навигация не удалась, например, если указанный URI не является допустимой страницей или не может быть преобразован в допустимую страницу, будет NavigationFailed
событие NavigationFailed
. В случае событий NavigationStopped
или NavigationFailed
эквивалентный метод не вызывается на самой странице.
В случае, если навигация продолжается, как и ожидалось, событие Navigated
будет вызвано на кадре. Затем следует вызов метода OnNavigatedFrom
(на OnNavigatedFrom
странице) и метода OnNavigatedTo
(на переходящей странице). Наконец, если URI содержит фрагмент, событие FragmentNavigation
вызывается во фрейме, после чего OnFragmentNavigation
метод OnFragmentNavigation
на странице, к которой осуществляется переход. Как вы видите, OnNavigatedTo
и OnFragmentNavigation
ссылаются в начале этого сообщения, образуют заключительный этап последовательности навигации и являются лучшим местом для извлечения либо строки запроса, либо фрагмента из URI навигации.
Другая концепция, которая была перенесена из Интернета, это концепция отображения или перезаписи URI. Для Silverlight для настольных компьютеров это было введено, прежде всего, как способ для приложения отображать удобочитаемые URL-адреса глубоких ссылок. В контексте приложения Windows Phone пользователь никогда не увидит URI страницы, к которой он перемещается. Тем не менее, все еще существуют обстоятельства, при которых имеет смысл выполнять сопоставление URI. Возьмите предыдущий пример, где приложение переходило к CustomerDetailsPage
и предоставляло идентификатор клиента в качестве параметра. Если имя этой страницы изменяется, или страница перемещается в подпапку, или даже если имя параметра изменяется с customerId на, возможно, просто ID, в каждом из этих случаев вам необходимо убедиться, что каждый метод навигации обновлен. Альтернативой может быть определение сопоставления URI для отображения страницы сведений о клиенте. Например:
/customer/{id} => /CustomerDetailsPage.xaml?customerId={id}
Теперь, если произойдет какое-либо из обсуждавшихся изменений, все, что вам нужно будет сделать, это изменить отображение:
/customer/{id} => /CustomerInfoPage.xaml?customerId={id} /customer/{id} => /Pages/CustomerDetailsPage.xaml?customerId={id} /customer/{id} => /CustomerDetailsPage.xaml?Id={id}
Существует два варианта определения сопоставления URI: вы можете просто создать экземпляр класса URIMapper и назначить его URIMapper
в фрейме, или вы можете создать URIMapper
как ресурс в файле App.xaml
. Последнее облегчает поиск и обновление URIMapper
.
<Application x:Class="CustomerNavigationSample.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone" xmlns:Navigation="clr-namespace:System.Windows.Navigation;assembly=Microsoft.Phone" > <Application.Resources> <Navigation:URIMapper x:Key="Mapper"> <Navigation:URIMapper.URIMappings> <Navigation:URIMapping URI="/customer/{id}" MappedURI="/CustomerDetailsPage.xaml?customerId={id}" /> </Navigation:URIMapper.URIMappings> </Navigation:URIMapper> </Application.Resources> … </Application>
После определения URIMapper
в App.xaml
вам необходимо назначить его PhoneApplicationFrame
в файле App.xaml.cs
public App() { // Global handler for uncaught exceptions. UnhandledException += Application_UnhandledException; // Standard Silverlight initialization InitializeComponent(); // Phone-specific initialization InitializePhoneApplication(); RootFrame.URIMapper = Application.Current.Resources["Mapper"] as URIMapper; … }
Теперь, когда сопоставление URI определено, вы можете перейти на страницу сведений о клиенте, используя следующую информацию, независимо от того, изменяется ли на странице имя, местоположение или имя параметра (при условии, конечно, что сопоставление обновлено).
this.NavigationService.Navigate(new URI("/customer/12345", URIKind.Relative));
Я оставлю вас с заключительным замечанием о том, что это разделение навигационной цели и реализации страницы является сегодня полезной концепцией в Windows Phone, но становится еще более актуальным, когда вы смотрите на возможности глубокого связывания Mango. Обновление Mango для Windows Phone представит глубокую ссылку как из Start Tiles, так и из Toast Notifications. Поскольку уведомления Toast чаще всего отправляются с сервера, который не должен знать или не заботиться о том, как реализовано приложение телефона, он может отделить навигационное намерение от особенностей приложения, что важно для обеспечения того, чтобы сервер и приложение были версионированы. независимо. Например, сервер может отправить следующее уведомление о тосте.
<?xml version="1.0" encoding="utf-8"?> <wp:Notification xmlns:wp="WPNotification"> <wp:Toast> <wp:Text1>Customer</wp:Text1> <wp:Text2>Bob Jones</wp:Text2> <wp:Param>/customer/12345</wp:Param> </wp:Toast> </wp:Notification>
Это будет выглядеть как всплывающее уведомление пользователя телефона с текстом «Клиент Боб Джонс» (аналог входящего SMS-сообщения). Когда они нажимают на уведомление, приложение запускается, и значение элемента Param “/customer/12345”
будет интерпретироваться приложением, чтобы определить, какую страницу отображать. Используя сопоставление URI, которое мы определили ранее, это приведет к “/CustomerDetailsPage.xaml?customerId=12345”
. Однако приложение может быть реструктурировано, и отображение URI изменилось без необходимости изменения кода сервера.
Надеемся, что после прочтения этого поста у вас будет хорошее представление о службе навигации Windows Phone и соответствующих событиях и методах. Обладая этими знаниями, вы сможете эффективно передавать данные между страницами, в то же время обрабатывая различные сценарии, возникающие в результате захоронения .