Цель работы: освоить методику организации навигации в приложениях
С точки зрения пользователя перемещения по страницам приложения происходят в ответ на взаимодействие пользователя с некими элементами управления, либо – как реакция на некоторые события, соответствующие сценарию работы приложения.
Приложение для Windows Phone содержит базовый элемент Microsoft.Phone.Controls.PhoneApplicationFrame (http://msdn.microsoft.com/en-us/library/windowsphone/develop/microsoft.phone.controls.phoneapplicationframe%28v=vs.105%29.aspx), так называемую рамку, которая, в свою очередь, служит контейнером для элементов Microsoft.Phone.Controls.PhoneApplicationPage (http://msdn.microsoft.com/en-us/library/windowsphone/develop/microsoft.phone.controls.phoneapplicationpage%28v=vs.105%29.aspx), то есть – для страниц приложения. Страницы, в свою очередь, могут содержать другие элементы управления, некоторые из которых служат для организации содержимого страницы, некоторые служат для отображения содержимого и организации непосредственного взаимодействия с пользователем. Элементы управления, которые отвечают за организацию содержимого страницы, это, например, System.Windows.Control.Grid, то есть – сетка для содержимого, Microsoft.Phone.Controls.Panorama – то есть элемент управления для организации панорамного просмотра данных, с общим заголовком, располагающийся на странице и содержащий элементы Microsoft.Phone.Controls.PanoramaItem. Это – элемент управления Microsoft.Phone.Controls.Pivot, который содержит элементы Microsoft.Phone.Controls.PivotItem и позволяет организовывать данные на странице, снабжая их отдельными заголовками.
Корневая рамка приложения, PhoneApplicationFrame, определяется в файле App.xaml.cs, она носит имя RootFrame, в приложении может быть только одна рамка. В свою очередь, XAML-страницы приложения – это объекты PhoneApplicationPage – их в приложении может быть столько, сколько нужно для решения задач, возложенных на него разработчиком.
Помимо обычных элементов управления, на странице можно описать так называемую панель приложения, Microsoft.Phone.Shell.ApplicationBar (http://msdn.microsoft.com/en-us/library/windowsphone/develop/microsoft.phone.shell.applicationbar%28v=vs.105%29.aspx). Уже из пространства имён панели приложения ясно, что перед нами системный объект. Поэтому и работа с ним из кода выглядит не так, как работа с обычными элементами управления. Панель приложения располагается в нижней части страницы. Фактически, это – комбинация панели инструментов и меню. "Панель инструментов" может содержать до четырех кнопок с пиктограммами для организации быстрого доступа к наиболее востребованным командам, а в меню, при необходимости, выносятся другие команды. Если на странице нужна функциональность, подобная функциональности панели инструментов и меню, желательно реализовать её именно с помощью панели приложения. Пользователи платформы Windows Phone привыкли к подобному средству взаимодействия с приложением, знают, чего от него можно ожидать, в большинстве случаев панель приложения – это наилучший выбор. Однако, не стоит забывать о том, что если в приложении, например, в графическом редакторе, нужна особая функциональность меню и панелей инструментов, не запрещено реализовывать её средствами, избранными разработчиком. Помимо команд, которые отвечают за выполнение некоторых действий, имеющих отношение к текущей странице приложения, панель приложения можно использовать и для организации перехода на другие страницы, то есть – она является одним из инструментов, который применим в навигации по страницам.
Разрабатывая систему навигации для приложения, стоит помнить о роли кнопки Назад, которая позволяет пользователю вернуться на предыдущую страницу. Не нужно создавать элементы управления, дублирующие её функциональность. Кроме того, стоит постоянно помнить о том, что приложения для Windows Phone – это приложения для мобильных устройств. Чем проще и понятнее будет система навигации по приложению, чем меньше действий пользователю придётся совершить для того, чтобы выполнить то, ради чего он запустил приложение, тем выше шансы приложения на успех. Если без некоторого экрана в вашем приложении можно обойтись – значит избавьтесь от него, сосредоточьтесь на основной задаче приложения, помните о том, что приложением могут пользоваться в условиях, когда на то, чтобы разбираться в сложной структуре его страниц, просто нет времени.
Для того, чтобы освоить задачи по организации навигации в приложениях, создадим учебное приложение, реализующее следующие возможности:
Создадим проект приложения P4_1 на основе шаблона Приложение Windows Phone. Добавим в проект приложения страницу CommonPage.xaml, она будет создана по шаблону элемента Страница Windows Phone в книжной ориентации и представлять собой пример некоей обычной страницы приложения. Так же создадим в проекте папку Pages и добавим страницу Settings.xaml, которая она создана по шаблону Сводная страница Windows Phone, например, такая страница может использоваться для организации настроек приложения с помощью элемента управления Microsoft.Phone.Controls.Pivot). Добавим в приложение еще одну страницу, About.xaml, созданную по шаблону Страница Windows Phone в книжной ориентации. Будем использовать их для демонстрации организации навигации в приложении. Сейчас проект выглядит так, как показано на рис. 17.1.
(рис 17.1) Окно проекта P4_1 после добавления нескольких страниц
На страницу MainPage.xaml добавим текстовое поле и кнопку с надписью "Вход", свойство Content кнопки установим в значение "Вход". Мы хотим реализовать здесь следующие возможности. Кнопка cmdEnter служит для перехода на страницу CommonPage, при этом переход осуществляется только тогда, когда заполнено текстовое поле. На практике подобный сценарий можно использовать, например, для создания страницы приложения, которая используется для ввода учетных данных. После нажатия на кнопку учетные данные проходят проверку, если они соответствуют, например, некоей учетной записи пользователя, осуществляется переход на следующую страницу приложения, если нет - пользователю можно показать сообщение, где говорится об ошибке ввода данных, или о другой ошибке, из-за которой данные не могут быть проверены. Например – такое возможно, если мы пытаемся подключиться к некоей онлайновой службе, а соединения с интернетом нет, либо если данные, которые ввёл пользователь, не прошли некоторую формальную проверку, например, поле, в котором должен содержаться адрес электронной почты, заполнено неверно, поле, где ожидается данные, имеющие определенную длину, состоящие из определенного набора символов (номер телефона, например), содержит данные неверного размера.
Подобную задачу можно решить несколькими способами. Можно, перехватывая событие текстового поля TextChanged, проверять введенные данные и, если они введены верно, устанавливать в True свойство кнопки IsEnabled, которое было до этого установлено в False. То есть, пользователь сможет нажать на кнопку, обработчик события Click которой содержит код для перехода на другую страницу, лишь тогда, когда данные введены верно. Можно, в обработчике события Click кнопки проверить условие правильности ввода данных (или произвести попытку авторизации в интернет-сервисе, если речь идет о приложении, которое используется для работы с сервисом, требующим авторизации). Мы поступим иначе – воспользуемся возможностью отмены навигации в том случае, если текстовое поле осталось незаполненным и выведем при этом пользователю соответствующее сообщение.
Кроме того, конечный результат работы должен реализовать следующую логику. Если пользователь, попадая при первом запуске приложения на его начальную страницу, с помощью инструментов которой он может авторизоваться в некоей службе, вводит учетные данные и, при успешной авторизации, попадает на следующую страницу приложения (она будет содержать некоторые данные, загруженные с сервиса, что-то вроде списка контактов пользователя, списка сообщений и т.д.), то при последующих запусках приложения подразумевается, что он остаётся авторизованным в сервисе. Например, приложение может попытаться выполнить автоматический вход в сервис, используя ранее введенные учетные данные (хотя, следует избегать хранения учетных данных пользователей), или, если при входе выдаётся некий секретный ключ, использовать этот ключ от предыдущей сессии, если он всё еще актуален. При этом показывает первую страницу приложения не нужно.
Полная реализация этого механизма требует анализа некоторых сохранённых в предыдущем сеансе работы данных, эти механизмы мы рассмотрим позднее, сейчас мы реализуем следующую возможность.
Когда пользователю разрешено перейти на следующую страницу, он не может вернуться на стартовую страницу, которая является страницей авторизации, просто нажав на кнопку Назад. Для возврата ему нужно выполнить особую команду. В нашем случае это будет команда Выйти из системы, которая будет находиться на странице Settings.xaml. Но возврат со страницы Settings.xaml на страницу MainPage.xaml – это так же не обычный переход, после которого можно воспользоваться кнопкой Назад для возврата на Settings.xaml. Это переход, выполнение которого подразумевает невозможность дальнейшей работы с программой без ввода учетных данных на MainPage.xaml. Подобная логика переходов по страницам приложения понятна пользователям. Внутри приложения, при переходе от страницы CommonPage.xaml к страницам Settings.xaml и About.xaml, действует стандартный механизм обработки переходов.
На рис. 17.2. приведена готовая страница MainPage.xaml.
(рис 17.2) Страница MainPage.xaml
Обратите внимание на то, что эта копия экрана снята при запуске приложения в режиме отладки, при этом показатели производительности, которые обычно выводятся в правой части экрана, не отображаются. Для того, чтобы не выводить их, мы закомментировали в файле App.xaml.cs строку
Application.Current.Host.Settings.EnableFrameRateCounter = true;
Показатели производительности полезны при отладке, если же речь идёт о копиях экрана, которые снимают для того, чтобы включить в материалы, необходимые для отправки приложения в Магазин (а иногда подобные копии экранов попадаются у приложений, опубликованных в Магазине), их нужно скрыть для того, чтобы не вводить пользователей в заблуждение относительно интерфейса программы.
В Листинге 17.1 приведен код страницы MainPage.xaml
<phone:PhoneApplicationPage
x:Class="P4_1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="Portrait" Orientation="Portrait"
shell:SystemTray.IsVisible="False">
<!--LayoutRoot представляет корневую сетку, где размещается все содержимое страницы-->
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!--TitlePanel содержит имя приложения и заголовок страницы-->
<StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
<TextBlock Text="НАВИГАЦИЯ" Style="{StaticResource PhoneTextNormalStyle}" Margin="12,0"/>
<TextBlock Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}" Text="вход"/>
</StackPanel>
<!--ContentPanel — поместите здесь дополнительное содержимое-->
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="10,0,14,0">
<TextBlock HorizontalAlignment="Left" Margin="31,87,0,0" T
TextWrapping="Wrap"
Text="Имя пользователя" VerticalAlignment="Top" Width="179"/>
<Button x:Name="cmdEnter" Content="Вход" HorizontalAlignment="Left" Margin="31,221,0,0"
VerticalAlignment="Top" Width="132" Click="cmdEnter_Click"/>
<TextBox x:Name="txtLogin" HorizontalAlignment="Left"
Height="73" Margin="24,115,0,0"
Grid.Row="1" TextWrapping="Wrap" VerticalAlignment="Top" Width="425"/>
</Grid>
</Grid>
</phone:PhoneApplicationPage>
На копии экрана, кроме того, видно, что при выводе этой страницы не отображается системная строка состояния, расположенная по умолчанию в верхней части экрана. Мы скрыли её благодаря следующей настройке: shell:SystemTray.IsVisible="False".
Как можно видеть из кода, по нажатию на кнопку cmdEnter выполняется вызов обработчика её события Click. Код файла MainPage.xaml.cs приведен в Листинге 17.2. Для организации навигации по страницам приложения используется объект System.Windows.Navigation.NavigationService (http://msdn.microsoft.com/en-us/library/windowsphone/develop/system.windows.navigation.navigationservice%28v=vs.105%29.aspx)
using System;
using System.Windows;
using System.Windows.Navigation;
using Microsoft.Phone.Controls;
namespace P4_1
{
public partial class MainPage : PhoneApplicationPage
{
// Конструктор
public MainPage()
{
InitializeComponent();
}
private void cmdEnter_Click(object sender, RoutedEventArgs e)
{
NavigationService.Navigate(new Uri("/CommonPage.xaml", UriKind.Relative));
}
protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
{
base.OnNavigatingFrom(e);
if (txtLogin.Text == "")
{
MessageBox.Show("Нужно ввести учетные данные");
e.Cancel = true;
}
}
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
NavigationService.RemoveBackEntry();
base.OnNavigatedFrom(e);
}
}
}
Здесь мы используем обработчик события нажатия на кнопку для навигации к странице CommonPage.xaml. Затем мы обрабатываем событие OnNavigatingFrom. Оно вызывается до выполнения перехода, здесь мы можем, в частности, отменить переход. Мы проверяем, заполнено ли текстовое поле, если это не так – показываем пользователю соответствующее сообщение и отменяем навигацию. В противном случае никаких действий не предпринимаем. Если же поле заполнено, в обработчике OnNavigatingFrom мы не предпринимаем никаких действий, вызывается обработчик OnNavigatedFrom. На данном этапе стек навигации уже содержит запись о странице MainPage.xaml, при обычном ходе событий это позволит перейти со следующей страницы на данную. Нам нужно иное поведение системы, поэтому мы удаляем запись из журнала и пользователь видит страницу CommonPage.xaml, рис. 17.3.
(рис 17.3) Страница CommonPage.xaml
На ней размещена кнопка-гиперссылка для перехода на страницу сведений о программе. Как можно видеть из XAML-кода страницы (Листинг 17.3) настройка адреса для перехода при использовании кнопки-гиперссылки, производится непосредственно в разметке страницы, обработчик события нам здесь не нужен.
Кроме того, на странице используется панель приложения. Здесь имеется одна кнопка, изображение для которой находится в папке Images нашего проекта (рис. 17.4.).
(рис 17.4) Структура проекта после добавления изображения для элемента панели приложения
Здесь использовано стандартное изображение, набор таких изображений, которые присутствуют в поставке средств разработки, можно найти по адресу C:\Program Files (x86)\Microsoft SDKs\Windows Phone\v8.0\Icons. Причем, здесь имеется папки с готовыми изображениями Dark и Light. Значки, расположенные в первой из них, можно использовать и при установках светлой темы, и при установках тёмной темы на устройстве. Они представляют собой PNG-изображения с прозрачным фоном и изображениями, выполненными белым цветом. Такой же подход следует использовать при создании собственных значков для кнопок панели управления.
<phone:PhoneApplicationPage
x:Class="P4_1.CommonPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="Portrait" Orientation="Portrait"
mc:Ignorable="d"
shell:SystemTray.IsVisible="True">
<!--LayoutRoot представляет корневую сетку, где размещается все содержимое страницы-->
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!--TitlePanel содержит имя приложения и заголовок страницы-->
<StackPanel Grid.Row="0" Margin="12,17,0,28">
<TextBlock Text="НАВИГАЦИЯ" Style="{StaticResource PhoneTextNormalStyle}"/>
<TextBlock Text="страница" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
</StackPanel>
<!--ContentPanel – поместите здесь дополнительное содержимое-->
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<HyperlinkButton Content="О программе" HorizontalAlignment="Left" Margin="140,192,0,0"
VerticalAlignment="Top" NavigateUri="/About.xaml"/>
</Grid>
</Grid>
<phone:PhoneApplicationPage.ApplicationBar>
<shell:ApplicationBar IsVisible="True" IsMenuEnabled="True" Mode="Minimized">
<shell:ApplicationBarIconButton IconUri="/Images/questionmark.png"
Text="О программе" Click="ApplicationBarIconButton_Click"/>
<shell:ApplicationBar.MenuItems>
<shell:ApplicationBarMenuItem Text="Настройки"
Click="ApplicationBarMenuItem_Click"/>
<shell:ApplicationBarMenuItem Text="Команда меню"/>
</shell:ApplicationBar.MenuItems>
</shell:ApplicationBar>
</phone:PhoneApplicationPage.ApplicationBar>
</phone:PhoneApplicationPage>
Обратите внимание на то, что у панели приложения свойство Mode установлено в значение Minimized. Это приводит к тому, что панель занимает минимум места на экране, однако, для доступа к кнопкам её нужно развернуть. Какую именно панель использовать – стандартную или уменьшенную – можно решить, основываясь на необходимости постоянной доступности её кнопок. Кнопкам и командам меню панели можно назначать обработчики, они располагаются в коде страницы (Листинг 17.4.).
using System;
using System.Windows.Navigation;
using Microsoft.Phone.Controls;
namespace P4_1
{
public partial class CommonPage : PhoneApplicationPage
{
public CommonPage()
{
InitializeComponent();
}
private void ApplicationBarMenuItem_Click(object sender, EventArgs e)
{
NavigationService.Navigate(new Uri("/Pages/Settings.xaml", UriKind.Relative));
}
private void ApplicationBarIconButton_Click(object sender, EventArgs e)
{
NavigationService.Navigate(new Uri("/About.xaml", UriKind.Relative));
}
}
}
Навигация с помощью элементов панели приложения ничем не отличается от навигации с помощью кнопок. Обратите внимание на обращение к странице, расположенной не в корневом разделе проекта, а в одном из подразделов. Путь к странице Settings.xaml (рис. 17.4.) указывается относительно корневого раздела: /Pages/Settings.xaml.
На странице Settings.xaml (Листинг 17.5) мы использовали элемент управления Pivot (создав её по соответствующему шаблону, хотя это не принципиально, можно добавить его на страницу самостоятельно), на одном из экранов которого расположена кнопка для "выхода из системы", то есть – в нашем случае для перехода на первую страницу приложения и очистки стека навигации.
<phone:PhoneApplicationPage
x:Class="P4_1.Pages.Settings"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="Portrait" Orientation="Portrait"
shell:SystemTray.IsVisible="True">
<!--LayoutRoot представляет корневую сетку, где размещается все содержимое страницы-->
<Grid x:Name="LayoutRoot" Background="Transparent">
<!--Элемент управления Pivot-->
<phone:Pivot Title="НАВИГАЦИЯ">
<!--Первый элемент Pivot-->
<phone:PivotItem Header="цвет">
<Grid/>
</phone:PivotItem>
<!--Второй элемент Pivot-->
<phone:PivotItem Header="размер">
<Grid/>
</phone:PivotItem>
<!--Третий элемент Pivot-->
<phone:PivotItem Header="общие">
<Button x:Name="cmdLogOut" Content="Выйти из системы"
HorizontalAlignment="Left" Height="83" Margin="52,84,0,0"
VerticalAlignment="Top" Width="259" Click="cmdLogOut_Click"/>
</phone:PivotItem>
</phone:Pivot>
</Grid>
В файле кода страницы (Листинг 17.6) мы, обрабатывая событие кнопки cmdLogOut, выполняем переход на страницу MainPage.xaml и в событии OnNavigatedFrom очищаем стек. В нашем случае такой подход работает, однако, если бы мы инициировали переход с данной страницы на другие страницы, каждый раз при вызове события OnNavigatedFrom стек не нужно было бы очищать. Следовало бы проверять, на какую страницу осуществляется переход (например, воспользовавшись свойством CurrentSource объекта NavigationService), и очищать стек лишь при переходе на MainPage.xaml. В нашем случае это не нарушает логику приложения, в иных случаях нужно обратить на это внимание.
</phone:PhoneApplicationPage>
using System;
using System.Windows;
using System.Windows.Navigation;
using Microsoft.Phone.Controls;
namespace P4_1.Pages
{
public partial class Settings : PhoneApplicationPage
{
public Settings()
{
InitializeComponent();
}
private void cmdLogOut_Click(object sender, RoutedEventArgs e)
{
NavigationService.Navigate(new Uri("/MainPage.xaml", UriKind.Relative));
}
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
while (NavigationService.CanGoBack)
{
NavigationService.RemoveBackEntry();
}
base.OnNavigatedFrom(e);
}
}
}
В этой лабораторной работе мы рассмотрели организацию навигации по приложению с использованием кнопок, кнопок-гиперссылок, элементов управления панели приложения, рассмотрели обработку событий переходов страниц и управление стеком переходов для организации особых сценариев навигации.
Продумайте систему навигации по приложению, идею которого вы выработали после проведения предыдущего семинарского занятия. Подумайте над тем, нужна ли в вашем приложении панель приложения и если нужна – определите примерный состав её кнопок и команд. Создайте новый проект, добавьте в него страницы, которые будут содержаться в вашем приложении, при необходимости – настройте панели приложения и организуйте навигацию между ними в соответствии с особенностями приложения. Убедитесь в том, что навигация по приложению интуитивно понятна, предложите кому-нибудь поработать с системой навигации и оценить – не вызывает ли работа с ней затруднений.
К данной лекции подготовлено видеоприложение и демонстрационный программный проект.
Цель работы: освоить методику организации навигации в приложениях
С точки зрения пользователя перемещения по страницам приложения происходят в ответ на взаимодействие пользователя с некими элементами управления, либо – как реакция на некоторые события, соответствующие сценарию работы приложения.
Приложение для Windows Phone содержит базовый элемент Microsoft.Phone.Controls.PhoneApplicationFrame (http://msdn.microsoft.com/en-us/library/windowsphone/develop/microsoft.phone.controls.phoneapplicationframe%28v=vs.105%29.aspx), так называемую рамку, которая, в свою очередь, служит контейнером для элементов Microsoft.Phone.Controls.PhoneApplicationPage (http://msdn.microsoft.com/en-us/library/windowsphone/develop/microsoft.phone.controls.phoneapplicationpage%28v=vs.105%29.aspx), то есть – для страниц приложения. Страницы, в свою очередь, могут содержать другие элементы управления, некоторые из которых служат для организации содержимого страницы, некоторые служат для отображения содержимого и организации непосредственного взаимодействия с пользователем. Элементы управления, которые отвечают за организацию содержимого страницы, это, например, System.Windows.Control.Grid, то есть – сетка для содержимого, Microsoft.Phone.Controls.Panorama – то есть элемент управления для организации панорамного просмотра данных, с общим заголовком, располагающийся на странице и содержащий элементы Microsoft.Phone.Controls.PanoramaItem. Это – элемент управления Microsoft.Phone.Controls.Pivot, который содержит элементы Microsoft.Phone.Controls.PivotItem и позволяет организовывать данные на странице, снабжая их отдельными заголовками.
Корневая рамка приложения, PhoneApplicationFrame, определяется в файле App.xaml.cs, она носит имя RootFrame, в приложении может быть только одна рамка. В свою очередь, XAML-страницы приложения – это объекты PhoneApplicationPage – их в приложении может быть столько, сколько нужно для решения задач, возложенных на него разработчиком.
Помимо обычных элементов управления, на странице можно описать так называемую панель приложения, Microsoft.Phone.Shell.ApplicationBar (http://msdn.microsoft.com/en-us/library/windowsphone/develop/microsoft.phone.shell.applicationbar%28v=vs.105%29.aspx). Уже из пространства имён панели приложения ясно, что перед нами системный объект. Поэтому и работа с ним из кода выглядит не так, как работа с обычными элементами управления. Панель приложения располагается в нижней части страницы. Фактически, это – комбинация панели инструментов и меню. "Панель инструментов" может содержать до четырех кнопок с пиктограммами для организации быстрого доступа к наиболее востребованным командам, а в меню, при необходимости, выносятся другие команды. Если на странице нужна функциональность, подобная функциональности панели инструментов и меню, желательно реализовать её именно с помощью панели приложения. Пользователи платформы Windows Phone привыкли к подобному средству взаимодействия с приложением, знают, чего от него можно ожидать, в большинстве случаев панель приложения – это наилучший выбор. Однако, не стоит забывать о том, что если в приложении, например, в графическом редакторе, нужна особая функциональность меню и панелей инструментов, не запрещено реализовывать её средствами, избранными разработчиком. Помимо команд, которые отвечают за выполнение некоторых действий, имеющих отношение к текущей странице приложения, панель приложения можно использовать и для организации перехода на другие страницы, то есть – она является одним из инструментов, который применим в навигации по страницам.
Разрабатывая систему навигации для приложения, стоит помнить о роли кнопки Назад, которая позволяет пользователю вернуться на предыдущую страницу. Не нужно создавать элементы управления, дублирующие её функциональность. Кроме того, стоит постоянно помнить о том, что приложения для Windows Phone – это приложения для мобильных устройств. Чем проще и понятнее будет система навигации по приложению, чем меньше действий пользователю придётся совершить для того, чтобы выполнить то, ради чего он запустил приложение, тем выше шансы приложения на успех. Если без некоторого экрана в вашем приложении можно обойтись – значит избавьтесь от него, сосредоточьтесь на основной задаче приложения, помните о том, что приложением могут пользоваться в условиях, когда на то, чтобы разбираться в сложной структуре его страниц, просто нет времени.
Для того, чтобы освоить задачи по организации навигации в приложениях, создадим учебное приложение, реализующее следующие возможности:
Создадим проект приложения P4_1 на основе шаблона Приложение Windows Phone. Добавим в проект приложения страницу CommonPage.xaml, она будет создана по шаблону элемента Страница Windows Phone в книжной ориентации и представлять собой пример некоей обычной страницы приложения. Так же создадим в проекте папку Pages и добавим страницу Settings.xaml, которая она создана по шаблону Сводная страница Windows Phone, например, такая страница может использоваться для организации настроек приложения с помощью элемента управления Microsoft.Phone.Controls.Pivot). Добавим в приложение еще одну страницу, About.xaml, созданную по шаблону Страница Windows Phone в книжной ориентации. Будем использовать их для демонстрации организации навигации в приложении. Сейчас проект выглядит так, как показано на рис. 17.1.
(рис 17.1) Окно проекта P4_1 после добавления нескольких страниц
На страницу MainPage.xaml добавим текстовое поле и кнопку с надписью "Вход", свойство Content кнопки установим в значение "Вход". Мы хотим реализовать здесь следующие возможности. Кнопка cmdEnter служит для перехода на страницу CommonPage, при этом переход осуществляется только тогда, когда заполнено текстовое поле. На практике подобный сценарий можно использовать, например, для создания страницы приложения, которая используется для ввода учетных данных. После нажатия на кнопку учетные данные проходят проверку, если они соответствуют, например, некоей учетной записи пользователя, осуществляется переход на следующую страницу приложения, если нет - пользователю можно показать сообщение, где говорится об ошибке ввода данных, или о другой ошибке, из-за которой данные не могут быть проверены. Например – такое возможно, если мы пытаемся подключиться к некоей онлайновой службе, а соединения с интернетом нет, либо если данные, которые ввёл пользователь, не прошли некоторую формальную проверку, например, поле, в котором должен содержаться адрес электронной почты, заполнено неверно, поле, где ожидается данные, имеющие определенную длину, состоящие из определенного набора символов (номер телефона, например), содержит данные неверного размера.
Подобную задачу можно решить несколькими способами. Можно, перехватывая событие текстового поля TextChanged, проверять введенные данные и, если они введены верно, устанавливать в True свойство кнопки IsEnabled, которое было до этого установлено в False. То есть, пользователь сможет нажать на кнопку, обработчик события Click которой содержит код для перехода на другую страницу, лишь тогда, когда данные введены верно. Можно, в обработчике события Click кнопки проверить условие правильности ввода данных (или произвести попытку авторизации в интернет-сервисе, если речь идет о приложении, которое используется для работы с сервисом, требующим авторизации). Мы поступим иначе – воспользуемся возможностью отмены навигации в том случае, если текстовое поле осталось незаполненным и выведем при этом пользователю соответствующее сообщение.
Кроме того, конечный результат работы должен реализовать следующую логику. Если пользователь, попадая при первом запуске приложения на его начальную страницу, с помощью инструментов которой он может авторизоваться в некоей службе, вводит учетные данные и, при успешной авторизации, попадает на следующую страницу приложения (она будет содержать некоторые данные, загруженные с сервиса, что-то вроде списка контактов пользователя, списка сообщений и т.д.), то при последующих запусках приложения подразумевается, что он остаётся авторизованным в сервисе. Например, приложение может попытаться выполнить автоматический вход в сервис, используя ранее введенные учетные данные (хотя, следует избегать хранения учетных данных пользователей), или, если при входе выдаётся некий секретный ключ, использовать этот ключ от предыдущей сессии, если он всё еще актуален. При этом показывает первую страницу приложения не нужно.
Полная реализация этого механизма требует анализа некоторых сохранённых в предыдущем сеансе работы данных, эти механизмы мы рассмотрим позднее, сейчас мы реализуем следующую возможность.
Когда пользователю разрешено перейти на следующую страницу, он не может вернуться на стартовую страницу, которая является страницей авторизации, просто нажав на кнопку Назад. Для возврата ему нужно выполнить особую команду. В нашем случае это будет команда Выйти из системы, которая будет находиться на странице Settings.xaml. Но возврат со страницы Settings.xaml на страницу MainPage.xaml – это так же не обычный переход, после которого можно воспользоваться кнопкой Назад для возврата на Settings.xaml. Это переход, выполнение которого подразумевает невозможность дальнейшей работы с программой без ввода учетных данных на MainPage.xaml. Подобная логика переходов по страницам приложения понятна пользователям. Внутри приложения, при переходе от страницы CommonPage.xaml к страницам Settings.xaml и About.xaml, действует стандартный механизм обработки переходов.
На рис. 17.2. приведена готовая страница MainPage.xaml.
(рис 17.2) Страница MainPage.xaml
Обратите внимание на то, что эта копия экрана снята при запуске приложения в режиме отладки, при этом показатели производительности, которые обычно выводятся в правой части экрана, не отображаются. Для того, чтобы не выводить их, мы закомментировали в файле App.xaml.cs строку
Application.Current.Host.Settings.EnableFrameRateCounter = true;
Показатели производительности полезны при отладке, если же речь идёт о копиях экрана, которые снимают для того, чтобы включить в материалы, необходимые для отправки приложения в Магазин (а иногда подобные копии экранов попадаются у приложений, опубликованных в Магазине), их нужно скрыть для того, чтобы не вводить пользователей в заблуждение относительно интерфейса программы.
В Листинге 17.1 приведен код страницы MainPage.xaml
<phone:PhoneApplicationPage
x:Class="P4_1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="Portrait" Orientation="Portrait"
shell:SystemTray.IsVisible="False">
<!--LayoutRoot представляет корневую сетку, где размещается все содержимое страницы-->
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!--TitlePanel содержит имя приложения и заголовок страницы-->
<StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
<TextBlock Text="НАВИГАЦИЯ" Style="{StaticResource PhoneTextNormalStyle}" Margin="12,0"/>
<TextBlock Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}" Text="вход"/>
</StackPanel>
<!--ContentPanel — поместите здесь дополнительное содержимое-->
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="10,0,14,0">
<TextBlock HorizontalAlignment="Left" Margin="31,87,0,0" T
TextWrapping="Wrap"
Text="Имя пользователя" VerticalAlignment="Top" Width="179"/>
<Button x:Name="cmdEnter" Content="Вход" HorizontalAlignment="Left" Margin="31,221,0,0"
VerticalAlignment="Top" Width="132" Click="cmdEnter_Click"/>
<TextBox x:Name="txtLogin" HorizontalAlignment="Left"
Height="73" Margin="24,115,0,0"
Grid.Row="1" TextWrapping="Wrap" VerticalAlignment="Top" Width="425"/>
</Grid>
</Grid>
</phone:PhoneApplicationPage>
На копии экрана, кроме того, видно, что при выводе этой страницы не отображается системная строка состояния, расположенная по умолчанию в верхней части экрана. Мы скрыли её благодаря следующей настройке: shell:SystemTray.IsVisible="False".
Как можно видеть из кода, по нажатию на кнопку cmdEnter выполняется вызов обработчика её события Click. Код файла MainPage.xaml.cs приведен в Листинге 17.2. Для организации навигации по страницам приложения используется объект System.Windows.Navigation.NavigationService (http://msdn.microsoft.com/en-us/library/windowsphone/develop/system.windows.navigation.navigationservice%28v=vs.105%29.aspx)
using System;
using System.Windows;
using System.Windows.Navigation;
using Microsoft.Phone.Controls;
namespace P4_1
{
public partial class MainPage : PhoneApplicationPage
{
// Конструктор
public MainPage()
{
InitializeComponent();
}
private void cmdEnter_Click(object sender, RoutedEventArgs e)
{
NavigationService.Navigate(new Uri("/CommonPage.xaml", UriKind.Relative));
}
protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
{
base.OnNavigatingFrom(e);
if (txtLogin.Text == "")
{
MessageBox.Show("Нужно ввести учетные данные");
e.Cancel = true;
}
}
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
NavigationService.RemoveBackEntry();
base.OnNavigatedFrom(e);
}
}
}
Здесь мы используем обработчик события нажатия на кнопку для навигации к странице CommonPage.xaml. Затем мы обрабатываем событие OnNavigatingFrom. Оно вызывается до выполнения перехода, здесь мы можем, в частности, отменить переход. Мы проверяем, заполнено ли текстовое поле, если это не так – показываем пользователю соответствующее сообщение и отменяем навигацию. В противном случае никаких действий не предпринимаем. Если же поле заполнено, в обработчике OnNavigatingFrom мы не предпринимаем никаких действий, вызывается обработчик OnNavigatedFrom. На данном этапе стек навигации уже содержит запись о странице MainPage.xaml, при обычном ходе событий это позволит перейти со следующей страницы на данную. Нам нужно иное поведение системы, поэтому мы удаляем запись из журнала и пользователь видит страницу CommonPage.xaml, рис. 17.3.
(рис 17.3) Страница CommonPage.xaml
На ней размещена кнопка-гиперссылка для перехода на страницу сведений о программе. Как можно видеть из XAML-кода страницы (Листинг 17.3) настройка адреса для перехода при использовании кнопки-гиперссылки, производится непосредственно в разметке страницы, обработчик события нам здесь не нужен.
Кроме того, на странице используется панель приложения. Здесь имеется одна кнопка, изображение для которой находится в папке Images нашего проекта (рис. 17.4.).
(рис 17.4) Структура проекта после добавления изображения для элемента панели приложения
Здесь использовано стандартное изображение, набор таких изображений, которые присутствуют в поставке средств разработки, можно найти по адресу C:\Program Files (x86)\Microsoft SDKs\Windows Phone\v8.0\Icons. Причем, здесь имеется папки с готовыми изображениями Dark и Light. Значки, расположенные в первой из них, можно использовать и при установках светлой темы, и при установках тёмной темы на устройстве. Они представляют собой PNG-изображения с прозрачным фоном и изображениями, выполненными белым цветом. Такой же подход следует использовать при создании собственных значков для кнопок панели управления.
<phone:PhoneApplicationPage
x:Class="P4_1.CommonPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="Portrait" Orientation="Portrait"
mc:Ignorable="d"
shell:SystemTray.IsVisible="True">
<!--LayoutRoot представляет корневую сетку, где размещается все содержимое страницы-->
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!--TitlePanel содержит имя приложения и заголовок страницы-->
<StackPanel Grid.Row="0" Margin="12,17,0,28">
<TextBlock Text="НАВИГАЦИЯ" Style="{StaticResource PhoneTextNormalStyle}"/>
<TextBlock Text="страница" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
</StackPanel>
<!--ContentPanel – поместите здесь дополнительное содержимое-->
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<HyperlinkButton Content="О программе" HorizontalAlignment="Left" Margin="140,192,0,0"
VerticalAlignment="Top" NavigateUri="/About.xaml"/>
</Grid>
</Grid>
<phone:PhoneApplicationPage.ApplicationBar>
<shell:ApplicationBar IsVisible="True" IsMenuEnabled="True" Mode="Minimized">
<shell:ApplicationBarIconButton IconUri="/Images/questionmark.png"
Text="О программе" Click="ApplicationBarIconButton_Click"/>
<shell:ApplicationBar.MenuItems>
<shell:ApplicationBarMenuItem Text="Настройки"
Click="ApplicationBarMenuItem_Click"/>
<shell:ApplicationBarMenuItem Text="Команда меню"/>
</shell:ApplicationBar.MenuItems>
</shell:ApplicationBar>
</phone:PhoneApplicationPage.ApplicationBar>
</phone:PhoneApplicationPage>
Обратите внимание на то, что у панели приложения свойство Mode установлено в значение Minimized. Это приводит к тому, что панель занимает минимум места на экране, однако, для доступа к кнопкам её нужно развернуть. Какую именно панель использовать – стандартную или уменьшенную – можно решить, основываясь на необходимости постоянной доступности её кнопок. Кнопкам и командам меню панели можно назначать обработчики, они располагаются в коде страницы (Листинг 17.4.).
using System;
using System.Windows.Navigation;
using Microsoft.Phone.Controls;
namespace P4_1
{
public partial class CommonPage : PhoneApplicationPage
{
public CommonPage()
{
InitializeComponent();
}
private void ApplicationBarMenuItem_Click(object sender, EventArgs e)
{
NavigationService.Navigate(new Uri("/Pages/Settings.xaml", UriKind.Relative));
}
private void ApplicationBarIconButton_Click(object sender, EventArgs e)
{
NavigationService.Navigate(new Uri("/About.xaml", UriKind.Relative));
}
}
}
Навигация с помощью элементов панели приложения ничем не отличается от навигации с помощью кнопок. Обратите внимание на обращение к странице, расположенной не в корневом разделе проекта, а в одном из подразделов. Путь к странице Settings.xaml (рис. 17.4.) указывается относительно корневого раздела: /Pages/Settings.xaml.
На странице Settings.xaml (Листинг 17.5) мы использовали элемент управления Pivot (создав её по соответствующему шаблону, хотя это не принципиально, можно добавить его на страницу самостоятельно), на одном из экранов которого расположена кнопка для "выхода из системы", то есть – в нашем случае для перехода на первую страницу приложения и очистки стека навигации.
<phone:PhoneApplicationPage
x:Class="P4_1.Pages.Settings"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="Portrait" Orientation="Portrait"
shell:SystemTray.IsVisible="True">
<!--LayoutRoot представляет корневую сетку, где размещается все содержимое страницы-->
<Grid x:Name="LayoutRoot" Background="Transparent">
<!--Элемент управления Pivot-->
<phone:Pivot Title="НАВИГАЦИЯ">
<!--Первый элемент Pivot-->
<phone:PivotItem Header="цвет">
<Grid/>
</phone:PivotItem>
<!--Второй элемент Pivot-->
<phone:PivotItem Header="размер">
<Grid/>
</phone:PivotItem>
<!--Третий элемент Pivot-->
<phone:PivotItem Header="общие">
<Button x:Name="cmdLogOut" Content="Выйти из системы"
HorizontalAlignment="Left" Height="83" Margin="52,84,0,0"
VerticalAlignment="Top" Width="259" Click="cmdLogOut_Click"/>
</phone:PivotItem>
</phone:Pivot>
</Grid>
В файле кода страницы (Листинг 17.6) мы, обрабатывая событие кнопки cmdLogOut, выполняем переход на страницу MainPage.xaml и в событии OnNavigatedFrom очищаем стек. В нашем случае такой подход работает, однако, если бы мы инициировали переход с данной страницы на другие страницы, каждый раз при вызове события OnNavigatedFrom стек не нужно было бы очищать. Следовало бы проверять, на какую страницу осуществляется переход (например, воспользовавшись свойством CurrentSource объекта NavigationService), и очищать стек лишь при переходе на MainPage.xaml. В нашем случае это не нарушает логику приложения, в иных случаях нужно обратить на это внимание.
</phone:PhoneApplicationPage>
using System;
using System.Windows;
using System.Windows.Navigation;
using Microsoft.Phone.Controls;
namespace P4_1.Pages
{
public partial class Settings : PhoneApplicationPage
{
public Settings()
{
InitializeComponent();
}
private void cmdLogOut_Click(object sender, RoutedEventArgs e)
{
NavigationService.Navigate(new Uri("/MainPage.xaml", UriKind.Relative));
}
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
while (NavigationService.CanGoBack)
{
NavigationService.RemoveBackEntry();
}
base.OnNavigatedFrom(e);
}
}
}
В этой лабораторной работе мы рассмотрели организацию навигации по приложению с использованием кнопок, кнопок-гиперссылок, элементов управления панели приложения, рассмотрели обработку событий переходов страниц и управление стеком переходов для организации особых сценариев навигации.
Продумайте систему навигации по приложению, идею которого вы выработали после проведения предыдущего семинарского занятия. Подумайте над тем, нужна ли в вашем приложении панель приложения и если нужна – определите примерный состав её кнопок и команд. Создайте новый проект, добавьте в него страницы, которые будут содержаться в вашем приложении, при необходимости – настройте панели приложения и организуйте навигацию между ними в соответствии с особенностями приложения. Убедитесь в том, что навигация по приложению интуитивно понятна, предложите кому-нибудь поработать с системой навигации и оценить – не вызывает ли работа с ней затруднений.
К данной лекции подготовлено видеоприложение и демонстрационный программный проект.
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.