Разработка компьютерных игр для Windows Phone 7 с использованием технологий Silverlight и XNA

Навигация, ориентация экрана

Показывать лекцию целиком

Цель работы: Научиться создавать систему навигации в Silverlight-приложениях, управлять ориентацией страниц

29.1. Навигация по страницам

Silverlight-приложения обычно включают в себя несколько страниц, поэтому одной из первоочередных задач, которую должен научиться решать Silverlight-разработчик – это организация навигации по страницам. Создадим новый Silverlight-проект, назовем его P22_1.

Вызовем контекстное меню проекта и выберем команду Добавить>Создать элемент. Здесь, в окне создания нового элемента проекта, рис. 29.1., нам доступны различные виды страниц и программных файлов.

Сейчас нас интересует Страница Windows Phone в книжной ориентации. Мы собираемся разместить на этой странице некоторые подробности о программе, поэтому назовём её About.xaml и нажмём на кнопку Добавить.

(рис 29.1) Добавление нового элемента

Страница добавлена в проект, а именно, в проекте появился файл About.xaml и файл кода к нему – About.xaml.cs. То, что страница добавлена в проект, не означает добавления в проект автоматических механизмов навигации. Если попытаться запустить проект в эмуляторе или на устройстве, мы, как и прежде, увидим лишь главную страницу. Это означает, что нам нужно создать систему навигации по страницам самостоятельно.

Добавим в проект еще одну страницу – назовём её Game.xaml и выберем для неё шаблон Страница Windows Phone в альбомной ориентации.

Поменяем название приложения на страницах на "НАВИГАЦИЯ", заголовки страниц установим в значения "главная", "о программе" и "игра" для страниц MainPage.xaml, About.xaml и Game.xaml.

В итоге внешний вид Обозревателя решений нашего проекта стал таким, рис. 29.2.

(рис 29.2) Обозреватель решений для проекта P22_1

Пожалуй, самый простой способ организации навигации между страницами заключается в использовании так называемой кнопки-гиперссылки (элемент управления HyperlinkButton). Перетащим новую кнопку-гиперссылку на страницу MainPage, выведем на неё текст Играть (свойство Content), свойство этой кнопки NavigateUri установим в значение "/Game.xaml".

Фактически, эти действия привели к появлению в коде MainPage.xaml одной строчки следующего содержания, листинг 29.1.

          <HyperlinkButton Content="Играть" Height="30" HorizontalAlignment="Left" 
          Margin="141,211,0,0" Name="hyperlinkButton1" VerticalAlignment="Top" Width="200"
          NavigateUri="/Game.xaml" />

Дополнительный программный код при использовании данного элемента управления не требуется.

Если теперь запустить наш проект, мы сможем, коснувшись этой ссылки, перейти на страницу Game.xaml.

Для возврата на главную страницу мы можем воспользоваться аппаратной кнопкой Назад. Такая практика стандартна для Silverlight-приложений для Windows Phone.

Рассмотрим еще один подход, он заключается в использовании обычной кнопки (Button) и применении кода, расположенного в обработчике события нажатия на эту кнопку.

Добавим на главную страницу новый элемент управления Button, разместим на нём надпись О программе, и, выполнив двойной щелчок по кнопке, создадим обработчик её нажатия. Приведем обработчик к такому виду, листинг 29.2.

private void button1_Click(object sender, RoutedEventArgs e)
        {
            Uri about = new Uri("/About.xaml", UriKind.Relative);
            NavigationService.Navigate(about);
        }

Здесь мы сначала создали новый объект типа Uri (универсальный код ресурса), при его создании указали, во-первых, адрес страницы, на которую хотим перейти, он задаётся в строковом представлении, во-вторых, вид ссылки. В нашем случае это, то есть UriKind.Relative – относительная ссылка.

Далее, мы пользуемся классом NavigationService, и, в частности, его методом Navigate, которому и передаём только что сформированную ссылку на ресурс.

Класс Navigate, помимо переходов по Uri, предоставляет такие возможности, как перезагрузка текущей страницы (метод Refresh), переход к последней записи журнала переходов назад (GoBack), остановка еще не обработанных асинхронных переходов (StopLoading).

На рис. 29.3 вы можете видеть главную страницу нашего проекта на данном этапе работы.

(рис 29.3) Главная страница проекта

Когда на странице появляется несколько элементов управления, особенно, если они выполняют некоторую связанную друг с другом функциональность, удобно располагать эти элементы внутри собственной сетки (Grid). Для этого добавим на страницу новую сетку, воспользовавшись элементом управления Grid. По умолчанию сетка напоминает таблицу с одной ячейкой. Нам нужны две ячейки, поэтому щелкнем мышью по левой части элемента управления в той позиции, где исходный Grid надо разбить.

Указатель в этот момент представляет собой тонкий крестик, вспомогательной линией отображается место, где произойдёт разбиение. После того, как мы получили сетку, состоящую из двух строк и одного столбца, перетащим элементы управления в полученные ячейки. Теперь мы сможем, например, перетаскивать элементы управления в поле страницы, не манипулируя ими раздельно, а перемещая всю их сетку (за левый верхний угол), выравнивать их на странице, ориентируясь на сетку. На рис. 29.4 вы можете видеть сетку с элементами в процессе редактирования.

(рис 29.4) Сетка на странице, процесс редактирования

При запуске программы сетка, по умолчанию, не видна. При необходимости можно настроить множество свойств сетки, назначить обработчики событий. Обработчики событий сетки могут понадобиться, например, при обработке смены ориентации экрана.

Сейчас мы продолжим развивать наш пример, поработаем с кнопкой Назад.

29.2. Работа с кнопкой Назад

Кнопка Назад играет огромную роль в навигации. Если говорить о нашем приложении, то можно заметить, что по умолчанию она возвращает нас со страниц Game и About на главную страницу, при нажатии этой кнопки на главной странице мы выходим из программы.

Когда, в предыдущем примере, мы использовали клавиатуру для ввода имени пользователя, нажатие на кнопку Назад скрывало клавиатуру. Когда в том же примере на экран выводилось сообщение, кнопка Назад позволяла скрыть его окно. Это – типичное поведение кнопки Назад, которое можно наблюдать во множестве приложений для Windows Phone.

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

При этом обычное нажатие кнопки переносит нас на предыдущий экран в журнале, а длительное показывает в уменьшенном виде весь доступный журнал. На рис. 29.5. показан журнал переходов в эмуляторе, появившийся после длительного нажатия на кнопку Назад. Предварительно мы открывали различные приложения в эмуляторе и возвращались из них на домашний экран нажатием кнопки Start.

(рис 29.5) Результат длительного нажатия на кнопку Назад

Журнал можно перематывать, находить таким образом нужный экран и прикосновением к этому экрану активировать нужное приложение. При работе в Internet Explorer, который встроен в Windows Phone, кнопка Назад работает как соответствующая кнопка в обычном браузере – то есть – позволяет перемещаться по истории посещения страниц.

Функциональность кнопки Назад можно переопределять, однако, делая это, не следует вводить пользователя в заблуждение неожиданным поведением системы, придерживаясь той логики, которая описана выше. Если вы, всё же, вмешались в работу системы с кнопкой Назад, рекомендуется по повторному нажатию этой кнопки выполнить действие, которое ожидает пользователь, нажимая на неё. В целом, нажатие на кнопку Назад должно переводить приложение или систему в предшествующее текущей ситуации состояние.

Обратите внимание на XAML-код наших страниц. Уровень страницы, тег, включающий в себя все остальные, представлен объектом PhoneApplicationPage.

Нажатие на кнопку Назад – это событие уровня страницы. Для его перехвата, мы можем как вручную добавить код в редакторе, так и, перейдя в область настройки свойств элемента PhoneApplicationPage, добиться отображения его свойств в окне Свойства (рис. 29.6), и ввести имя для необходимого нам обработчика события. Это приведет как к подписке на событие, так и к созданию кода обработчика в соответствующем CS-файле.

(рис 29.6) Создаем обработчик события BackKeyPress

В итоге код описания свойств элемента PhoneApplicationPage принимает такой вид, как показано в листинге 29.3 (обратите внимание на новую строчку BackKeyPress="PhoneApplicationPage_BackKeyPress">

<phone:PhoneApplicationPage 
    x:Class="P22_1.Game"
    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="Landscape" Orientation="Landscape"
    mc:Ignorable="d" d:DesignHeight="480" d:DesignWidth="728"
    shell:SystemTray.IsVisible="True" BackKeyPress="PhoneApplicationPage_BackKeyPress">

В листинге 29.4 приведен пустой обработчик события

private void PhoneApplicationPage_BackKeyPress(object sender, System.ComponentModel.CancelEventArgs e)
        {

        }

Введем в обработчик следующий код, листинг 29.5.

        private void PhoneApplicationPage_BackKeyPress(object sender, System.ComponentModel.CancelEventArgs e)
        {
            MessageBoxResult msgRes = MessageBox.Show("Действительно хотите перейти на главную страницу?",
                "Подтверждение перехода",
                MessageBoxButton.OKCancel);
            if (msgRes == MessageBoxResult.Cancel)
            {
                e.Cancel = true;
            }
        }

Здесь мы формируем окно сообщения, ожидаем нажатия на одну из кнопок (ОК или Отмена) и записываем результат в переменную msgRes. После этого проверяем, нажал ли пользователь кнопку Отмена (Cancel). Если нажал, присваиваем свойству Cancel, которое имеет объект типа System.ComponentModel.CancelEventArgs значение True, что означает отмену операции.

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

На рис. 29.7 вы можете видеть страницу Game с сообщением, которое выводится после нажатия на кнопку Назад.

(рис 29.7) Результат нажатия на кнопку Назад

Обратите внимание на то, что в нашем приложении некоторые страницы имеют портретную ориентацию (это главная страница, страница информации о программе), некоторые – ландшафтную (страница игры). Эта ориентация не меняется при повороте экрана. Это – вполне обычная практика для некоторых приложений. Для других же изменение ориентации страницы при смене ориентации экрана – насущная необходимость. Например, веб-браузер потерял бы многое в удобстве использования, не меняй он ориентацию страницы при повороте экрана. Ориентацией страниц можно управлять, продолжим работу над нашим примером, настроив таким образом страницу About.

29.3. Управление ориентацией экрана

Мы хотели бы, чтобы страницы нашего приложения обладали бы следующими особенностями. Главная страница должна отображаться в портретной ориентации, игровая – в ландшафтной, а страница информации о программе должна менять ориентацию при повороте экрана.

Добавим на страницу надпись (элемент управления TextBlock) с текстом "Это информация о нашей программе", теперь перейдем в XAML-код страницы и найдем там строку SupportedOrientations="Portrait" Orientation="Portrait". Эта строка указывает на то, что страница поддерживает портретную ориентацию, и отображается так же в этой ориентации. Фактически, данная строка задаёт соответствующее свойство для PhoneApplicationPage. Свойство SupportedOrientation (PhoneApplicationPage.SupportedOrientation) может принимать следующие значения:

  • Portrait – потретная
  • Landscape – ландшафтная
  • PortraitOrLandscape – портретная и ландшафтная ориентация.
  • Свойство Orientation (это – свойство PhoneApplicationPage.Orinentation) можно установить в следующие значения:

  • Landscape – ландшафтный режим по умолчанию
  • LandscapeLeft – ландшафтный режим, телефон расположен горизонтально, на левом боку
  • LandscapeRight – ландшафтный режим, телефон расположен горизонтально, на правом боку
  • Portrait – портретный режим по умолчанию
  • PortraitUp – стандартный портретный режим (кнопки в нижней части)
  • PortraitDown – перевернутый портретный режим (кнопки в верхней части)
  • None – ориентация не задана
  • Мы установим свойство SupportedOrientation в значение PortraitOrLandscape, в итоге, код страницы, где это свойство настраивается, приобретет вид, показанный в листинге 29.6.

    <phone:PhoneApplicationPage 
        x:Class="P22_1.About"
        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="PortraitOrLandscape" Orientation="Portrait"
        mc:Ignorable="d" d:DesignHeight="768" d:DesignWidth="480"
        shell:SystemTray.IsVisible="True">

    Если сейчас мы запустим данный пример на телефоне или на эмуляторе, перейдем на страницу About.xaml и попытаемся поворачивать телефон, при любом его положении (а именно, речь идёт о стандартных положениях - LandscapeLeft, LandscapeRight, PortraitUp) страничка будет автоматически разворачиваться правильным образом. Этот механизм работает без дополнительных усилий с нашей стороны, однако, вполне возможно, что в вашем приложении нужно будет вносить какие-либо изменения в отображаемые на странице элементы при смене ориентации, выполнить какие-то другие действия. Для того, чтобы перехватить и обработать событие смены ориентации экрана, нам понадобится обработчик события OrientationChanged для объекта PhoneApplicationPage. Зададим обработчик этого события (в XAML-коде появится строка OrientationChanged="PhoneApplicationPage_OrientationChanged"), приведем его текст в About.xaml.cs к состоянию, показанному в листинге 29.7.

    private void PhoneApplicationPage_OrientationChanged(object sender, OrientationChangedEventArgs e)
            {
                textBlock1.Text = "Ориентация экрана: " + this.Orientation.ToString();
            }

    В результате, после открытия страницы мы видим в текстовом блоке тот текст, который задан на этапе разработки, а при поворотах экрана в поле выводятся сведения о текущей ориентации, рис. 29.8.

    (рис 29.8) Реакция программы на смену ориентации экрана

    Кроме того, можно управлять поворотом, например, основываясь на данных от сенсоров устройства, от гироскопа и акселерометра.

    29.4. Выводы

    В данной лабораторной работе мы научились организовывать навигацию по страницам с помощью элементов управления Button и HyperlinkButton, освоили работу с кнопкой Назад и управление ориентацией страниц.

    29.5. Задание

    Выясните, ограничивается ли возможность организации навигации по страницам Silverlight-приложений использованием элементов управления, рассмотренных в данной лабораторной работе.

    29.6. Дополнительные материалы

    К данной лабораторной работе прилагается видеоурок

    и демонстрационный проект.

    Вернуться к учебному плану