Сложные приёмы разработки приложений для Windows Phone 8

Разработка пользовательского элемента управления

Разбить на страницы
Показывать лекцию целиком

Цель работы: освоить методику создания пользовательских элементов управления

Пользовательские элементы управления

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

Сейчас мы создадим собственный элемент управления, работая в проекте приложения P3_1, который создан по шаблону Приложение Windows Phone.

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

Вызовем контекстное меню проекта и выберем команду Добавить >> Создать элемент. В появившемся окне Добавление нового элемента выберем Пользовательский элемент управления Windows Phone, дадим ему имя MyControl (рис. 13.1) и нажмём на кнопку Добавить.

(рис 13.1) Добавление нового пользовательского элемента управления

После добавления в проект нового пользовательского элемента управления окажется, что он представлен в виде файла MyControl.xaml, который содержит визуальное представление элемента, описанное с помощью XAML, и файла программного кода – MyControl.xaml.cs. Визуальное представление нового элемента управления можно редактировать с помощью встроенного конструктора, а можно (позже мы именно так и поступим) редактировать и настраивать в Blend. По умолчанию визуальная часть элемента управления представляет собой квадрат размером 480х480 пикселей (рис. 13.2). За его размеры отвечают свойства DesighHeight (высота) и DesighWidth (ширина), заданные в заголовке XAML-файла.

(рис 13.2) Новый элемент управления после его добавления в проект

Взглянем на код, который нам предлагается после создания элемента управления. В Листинге 13.1 представлен код файла MyControl.xaml, в Листинге 13.2 – код файла MyControl.xaml.cs.

<UserControl x:Class="P3_1.MyControl"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    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}"
    d:DesignHeight="480" d:DesignWidth="480">
    
    <Grid x:Name="LayoutRoot" Background="{StaticResource PhoneChromeBrush}">

    </Grid>
</UserControl>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Navigation;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Shell;

namespace P3_1
{
    public partial class MyControl : UserControl
    {
        public MyControl()
        {
            InitializeComponent();
        }
    }
}

Во-первых, можно заметить, что в элементе управления, в XAML-файле, использованы некоторые статические ресурсы, это закладывает основу для использования стандартных шрифтов и цветовых решений в нашем элементе управления. Можно заметить, что для размещения содержимого визуального интерфейса элемента управления предназначена сетка LayoutRoot.

Класс нашего элемента управления MyControl является наследником класса UserControl (http://msdn.microsoft.com/ru-ru/library/windowsphone/develop/system.windows.controls.usercontrol%28v=vs.105%29.aspx).

Для начала создадим визуальное представление нового элемента управления. Откроем наш проект в Blend командой Проект > Открыть в Blend, перейдем на страницу MyControl.xaml, изменим размеры элемента до 355х64 пикселя (рис. 13.3).

(рис 13.3) Начало работы над пользовательским элементом управления

Разместим на нём элемент управления Rectangle (Прямоугольник), найти его в Blend можно по адресу Активы > Фигуры > Rectangle, зададим ему размер 355х44, выровняв вертикально по центру элемента управления, а горизонтально – немного сместив влево. Для его параметра Stroke (Обводка) выберем вариант Нет кисти (Свойства > Кисть > Stroke > Нет кисти), рис. 13.4. В итоге, сейчас у нас есть прямоугольник без обводки, закрашенный белым цветом (свойство Fill).

(рис 13.4) Размещение на элементе управления прямоугольника

Мы хотим анимировать прямоугольник для того, чтобы он имитировал нечто вроде индикатора выполнения операции, сдвигаясь слева направо. Для этого выделим прямоугольник в панели Объекты и временная шкала и в верхней части этой панели нажмём на кнопку со знаком "+" (Создать…). Появится окно, Создание ресурса Storyboard, где нужно ввести имя раскадровки , которую мы создаём. Дадим ей имя ProgressStoryboard и нажмём ОК.

На панели временной шкалы переместим жёлтый маркер ко второй секунде и сдвинем левый край прямоугольника до тех пор, пока он не совпадёт с правым краем. Если теперь проиграть шкалу (рис. 13.5.) соответствующей кнопкой, окажется, что работает это именно так, как нам нужно.

(рис 13.5) Настройка анимации прямоугольника

Теперь поработаем с цветом прямоугольника. Установим жёлтый маркер в начало временной шкалы, выберем тот цвет (параметр прямоугольника Fill), с которого нужно начинать плавное изменение цвета, после чего установим маркер на отметку 2 секунды и выберем второй цвет. В итоге, у нас получится анимация в виде уменьшения размера прямоугольника, слева направо, с плавным изменением цвета. Фигура, которая до начала трансформации имела белый цвет, в начале становится синей, а после трансформации, превращается из синего прямоугольника в тонкую вертикальную зеленую черту (рис. 13.6.).

(рис 13.6) Завершение настроек в Blend

Работы в Blend окончены, выберем в нём команду Файл > Сохранить всё и вернемся в Visual Studio. Всё то, что мы делали в Blend, привело к изменениям в XAML-разметке, в Листинге 13.3 приведен код файла MyControl.xaml.

<UserControl x:Class="P3_1.MyControl"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    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}"
    d:DesignHeight="480" d:DesignWidth="480" 
    Width="356" Height="64">
	<UserControl.Resources>
		<Storyboard x:Name="ProgressStoryboard">
			<DoubleAnimation Duration="0:0:2" To="0.001" 
Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.ScaleX)" 
Storyboard.TargetName="rectangle" d:IsOptimized="True"/>
			<DoubleAnimation Duration="0:0:2" To="176.667" 
Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateX)" 
Storyboard.TargetName="rectangle" d:IsOptimized="True"/>
			<ColorAnimationUsingKeyFrames Storyboard.TargetProperty="(Shape.Fill).
(SolidColorBrush.Color)" Storyboard.TargetName="rectangle">
				<EasingColorKeyFrame KeyTime="0" 
Value="#FF410DF5"/>
				<EasingColorKeyFrame KeyTime="0:0:2" 
Value="#FF42DC20"/>
			</ColorAnimationUsingKeyFrames>
		</Storyboard>
	</UserControl.Resources>
    
    <Grid x:Name="LayoutRoot" Background="{StaticResource PhoneChromeBrush}">
    	<Rectangle x:Name="rectangle" Fill="#FFF4F4F5" 
HorizontalAlignment="Left" Height="44" VerticalAlignment="Top" 
Width="355" Margin="0,10,0,0" 
RenderTransformOrigin="0.5,0.5">
    		<Rectangle.RenderTransform>
    			<CompositeTransform/>
    		</Rectangle.RenderTransform>
    	</Rectangle>

    </Grid>
</UserControl>

В разметке мы видим описание раскадровки ProgressStoryboard, в области содержимого можно видеть код описания прямоугольника.

Уже сейчас мы можем добавить элемент управления на страницу приложения. Он автоматически отображается в Панели элементов, добавление его на страницу выглядит точно так же, как добавление обычных элементов. После добавления элемента на стартовую страницу приложения, дадим ему имя MyControlMainPage (рис. 13.7). Если запустить сейчас наш проект для отладки, окажется, что элемент управления выводится, содержит прямоугольник белого цвета, но не реагирует на воздействия пользователя. Так и должно быть – мы не создавали пока механизмы по его взаимодействию с пользователем и с другими элементами приложения.

(рис 13.7) Добавление пользовательского элемента управления на страницу

Поработаем с кодом элемента управления

Для начала зададим обработчик события DoubleTap для сетки LayoutRoot. В обработчике запустим анимацию командой ProgressStoryboard.Begin(). Если запустить сейчас проект для отладки, окажется, что элемент управления реагирует на двойное касание, меняя цвет и запуская анимацию изменения размера и изменения цвета.

Для того, чтобы можно было выводить с его помощью сообщение, текст которого можно настраивать, добавив в код его класса (в файле MyControl.xaml.cs) общедоступное свойство строкового типа с именем Message, указав возможность его чтения и установки извне и опишем событие ReadyToLoadPage.

Мы будем вызывать это событие, предварительно показав пользователю окно сообщения, после того, как завершится исполнение раскадровки. Для этого нам понадобится обработать событие раскадровки Completed, которое вызывается при её завершении. В итоге мы пришли к такому коду файла MyControl.xaml.cs, Листинг 13.4

using System;
using System.Windows;
using System.Windows.Controls;

namespace P3_1
{
    public partial class MyControl : UserControl
    {
        public event EventHandler ReadyToLoadPage;

        public string Message
        {
            get;
            set;
        }
        
        public MyControl()
        {
            InitializeComponent();
        }

        private void LayoutRoot_DoubleTap(object sender, System.Windows.Input.GestureEventArgs e)
        {
            ProgressStoryboard.Begin();
        }

        private void ProgressStoryboard_Completed(object sender, EventArgs e)
        {
            if (Message!=null) 
                MessageBox.Show(Message);
            ReadyToLoadEventCall();
        }

        private void ReadyToLoadEventCall()
        {
            if (this.ReadyToLoadPage != null)
                this.ReadyToLoadPage(new object(), new EventArgs());
        }
    }
}

Здесь мы, при обработке события завершения раскадровки ProgressStoryboard_Completed проверяем, задано ли свойство Message. Если задано – выводим сообщение. Приложение ожидает реакции пользователя на сообщение, когда пользователь отреагировал, вызывается метод ReadyToLoadEventCall. В этом методе мы проверяем, подключён ли обработчик события, и если это так – вызываем событие. При обработке события нам важно то, что оно произойдёт, поэтому передача параметров носит формальный характер.

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

Добавим в проект еще одну страницу (контекстное меню проекта, команда Добавить > Создать элемент > Страница Windows Phone в книжной ориентации, дадим ей имя NextPage.xaml).

На странице MainPage.xaml мы можем, во-первых, задать свойство элемента управления Message, запишем туда текст "Теперь можно продолжать!". Это свойство, как и при работе с обычными элементами управления, доступно в панели свойств. При группировке свойств по категориям оно будет находиться в категории Разное. Так же, зададим обработчик события ReadyToLoadPage (рис. 13.8.), оно будет перечислено среди прочих событий элемента управления, которые мы можем обрабатывать на странице приложения, для создания обработчика достаточно выполнить двойной щелчок по соответствующему полю.

(рис 13.8) Настройка пользовательского элемента управления на странице

В Листинге 13.5 приведен XAML-код страницы MainPage.xaml

<phone:PhoneApplicationPage
    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"
    xmlns:local="clr-namespace:P3_1"
    x:Class="P3_1.MainPage"
    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">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>

        
        <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
            <TextBlock Text="ПОЛЬЗОВАТЕЛЬСКИЕ ЭЛЕМЕНТЫ УПРАВЛЕНИЯ" 
Style="{StaticResource PhoneTextNormalStyle}" Margin="12,0"/>
            <TextBlock Text="пример" Margin="9,-7,0,0" 
Style="{StaticResource PhoneTextTitle1Style}"/>
        </StackPanel>

        <!--ContentPanel — поместите здесь дополнительное содержимое-->
        <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">

            <local:MyControl x:Name="MyControlMainPage" HorizontalAlignment="Left" 
Margin="51,128,0,0" VerticalAlignment="Top" 
ReadyToLoadPage="MyControlMainPage_ReadyToLoadPage" Message="Теперь можно продолжать!"/>

        </Grid>

    </Grid>

</phone:PhoneApplicationPage>

В обработчик события ReadyToLoadPage достаточно добавить команду перехода на нужную страницу.

В итоге код файла MainPage.xaml.cs будет выглядеть так, как показано в Листинге 13.6.

using System;
using System.Windows.Navigation;
using Microsoft.Phone.Controls;

namespace P3_1
{
    public partial class MainPage : PhoneApplicationPage
    {
        // Конструктор
        public MainPage()
        {
            InitializeComponent();
        }

        private void MyControlMainPage_ReadyToLoadPage(object sender, EventArgs e)
        {
            NavigationService.Navigate(new Uri("/NextPage.xaml", UriKind.Relative));
        }

    }
}

Выводы

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

Задание

Создайте проект приложения, добавьте в него пользовательский элемент управления, содержащий анимацию, которая запускается при касании этого элемента управления. Добавьте элемент управления на страницу MainPage.xaml и разместите на ней анимированную с помощью раскадровки геометрическую фигуру. Настройте поведение приложения так, чтобы раскадровка, описанная на странице MainPage.xaml запускалась после завершения раскадровки, описанной в пользовательском элементе управления.

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

К данной лекции подготовлено видеоприложение и демонстрационный программный проект.

Страницы:

Цель работы: освоить методику создания пользовательских элементов управления

Пользовательские элементы управления

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

Сейчас мы создадим собственный элемент управления, работая в проекте приложения P3_1, который создан по шаблону Приложение Windows Phone.

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

Вызовем контекстное меню проекта и выберем команду Добавить >> Создать элемент. В появившемся окне Добавление нового элемента выберем Пользовательский элемент управления Windows Phone, дадим ему имя MyControl (рис. 13.1) и нажмём на кнопку Добавить.

(рис 13.1) Добавление нового пользовательского элемента управления

После добавления в проект нового пользовательского элемента управления окажется, что он представлен в виде файла MyControl.xaml, который содержит визуальное представление элемента, описанное с помощью XAML, и файла программного кода – MyControl.xaml.cs. Визуальное представление нового элемента управления можно редактировать с помощью встроенного конструктора, а можно (позже мы именно так и поступим) редактировать и настраивать в Blend. По умолчанию визуальная часть элемента управления представляет собой квадрат размером 480х480 пикселей (рис. 13.2). За его размеры отвечают свойства DesighHeight (высота) и DesighWidth (ширина), заданные в заголовке XAML-файла.

(рис 13.2) Новый элемент управления после его добавления в проект

Взглянем на код, который нам предлагается после создания элемента управления. В Листинге 13.1 представлен код файла MyControl.xaml, в Листинге 13.2 – код файла MyControl.xaml.cs.

<UserControl x:Class="P3_1.MyControl"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    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}"
    d:DesignHeight="480" d:DesignWidth="480">
    
    <Grid x:Name="LayoutRoot" Background="{StaticResource PhoneChromeBrush}">

    </Grid>
</UserControl>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Navigation;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Shell;

namespace P3_1
{
    public partial class MyControl : UserControl
    {
        public MyControl()
        {
            InitializeComponent();
        }
    }
}

Во-первых, можно заметить, что в элементе управления, в XAML-файле, использованы некоторые статические ресурсы, это закладывает основу для использования стандартных шрифтов и цветовых решений в нашем элементе управления. Можно заметить, что для размещения содержимого визуального интерфейса элемента управления предназначена сетка LayoutRoot.

Класс нашего элемента управления MyControl является наследником класса UserControl (http://msdn.microsoft.com/ru-ru/library/windowsphone/develop/system.windows.controls.usercontrol%28v=vs.105%29.aspx).

Для начала создадим визуальное представление нового элемента управления. Откроем наш проект в Blend командой Проект > Открыть в Blend, перейдем на страницу MyControl.xaml, изменим размеры элемента до 355х64 пикселя (рис. 13.3).

(рис 13.3) Начало работы над пользовательским элементом управления

Разместим на нём элемент управления Rectangle (Прямоугольник), найти его в Blend можно по адресу Активы > Фигуры > Rectangle, зададим ему размер 355х44, выровняв вертикально по центру элемента управления, а горизонтально – немного сместив влево. Для его параметра Stroke (Обводка) выберем вариант Нет кисти (Свойства > Кисть > Stroke > Нет кисти), рис. 13.4. В итоге, сейчас у нас есть прямоугольник без обводки, закрашенный белым цветом (свойство Fill).

(рис 13.4) Размещение на элементе управления прямоугольника

Мы хотим анимировать прямоугольник для того, чтобы он имитировал нечто вроде индикатора выполнения операции, сдвигаясь слева направо. Для этого выделим прямоугольник в панели Объекты и временная шкала и в верхней части этой панели нажмём на кнопку со знаком "+" (Создать…). Появится окно, Создание ресурса Storyboard, где нужно ввести имя раскадровки , которую мы создаём. Дадим ей имя ProgressStoryboard и нажмём ОК.

На панели временной шкалы переместим жёлтый маркер ко второй секунде и сдвинем левый край прямоугольника до тех пор, пока он не совпадёт с правым краем. Если теперь проиграть шкалу (рис. 13.5.) соответствующей кнопкой, окажется, что работает это именно так, как нам нужно.

(рис 13.5) Настройка анимации прямоугольника

Теперь поработаем с цветом прямоугольника. Установим жёлтый маркер в начало временной шкалы, выберем тот цвет (параметр прямоугольника Fill), с которого нужно начинать плавное изменение цвета, после чего установим маркер на отметку 2 секунды и выберем второй цвет. В итоге, у нас получится анимация в виде уменьшения размера прямоугольника, слева направо, с плавным изменением цвета. Фигура, которая до начала трансформации имела белый цвет, в начале становится синей, а после трансформации, превращается из синего прямоугольника в тонкую вертикальную зеленую черту (рис. 13.6.).

(рис 13.6) Завершение настроек в Blend

Работы в Blend окончены, выберем в нём команду Файл > Сохранить всё и вернемся в Visual Studio. Всё то, что мы делали в Blend, привело к изменениям в XAML-разметке, в Листинге 13.3 приведен код файла MyControl.xaml.

<UserControl x:Class="P3_1.MyControl"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    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}"
    d:DesignHeight="480" d:DesignWidth="480" 
    Width="356" Height="64">
	<UserControl.Resources>
		<Storyboard x:Name="ProgressStoryboard">
			<DoubleAnimation Duration="0:0:2" To="0.001" 
Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.ScaleX)" 
Storyboard.TargetName="rectangle" d:IsOptimized="True"/>
			<DoubleAnimation Duration="0:0:2" To="176.667" 
Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateX)" 
Storyboard.TargetName="rectangle" d:IsOptimized="True"/>
			<ColorAnimationUsingKeyFrames Storyboard.TargetProperty="(Shape.Fill).
(SolidColorBrush.Color)" Storyboard.TargetName="rectangle">
				<EasingColorKeyFrame KeyTime="0" 
Value="#FF410DF5"/>
				<EasingColorKeyFrame KeyTime="0:0:2" 
Value="#FF42DC20"/>
			</ColorAnimationUsingKeyFrames>
		</Storyboard>
	</UserControl.Resources>
    
    <Grid x:Name="LayoutRoot" Background="{StaticResource PhoneChromeBrush}">
    	<Rectangle x:Name="rectangle" Fill="#FFF4F4F5" 
HorizontalAlignment="Left" Height="44" VerticalAlignment="Top" 
Width="355" Margin="0,10,0,0" 
RenderTransformOrigin="0.5,0.5">
    		<Rectangle.RenderTransform>
    			<CompositeTransform/>
    		</Rectangle.RenderTransform>
    	</Rectangle>

    </Grid>
</UserControl>

В разметке мы видим описание раскадровки ProgressStoryboard, в области содержимого можно видеть код описания прямоугольника.

Уже сейчас мы можем добавить элемент управления на страницу приложения. Он автоматически отображается в Панели элементов, добавление его на страницу выглядит точно так же, как добавление обычных элементов. После добавления элемента на стартовую страницу приложения, дадим ему имя MyControlMainPage (рис. 13.7). Если запустить сейчас наш проект для отладки, окажется, что элемент управления выводится, содержит прямоугольник белого цвета, но не реагирует на воздействия пользователя. Так и должно быть – мы не создавали пока механизмы по его взаимодействию с пользователем и с другими элементами приложения.

(рис 13.7) Добавление пользовательского элемента управления на страницу

Поработаем с кодом элемента управления

Для начала зададим обработчик события DoubleTap для сетки LayoutRoot. В обработчике запустим анимацию командой ProgressStoryboard.Begin(). Если запустить сейчас проект для отладки, окажется, что элемент управления реагирует на двойное касание, меняя цвет и запуская анимацию изменения размера и изменения цвета.

Для того, чтобы можно было выводить с его помощью сообщение, текст которого можно настраивать, добавив в код его класса (в файле MyControl.xaml.cs) общедоступное свойство строкового типа с именем Message, указав возможность его чтения и установки извне и опишем событие ReadyToLoadPage.

Мы будем вызывать это событие, предварительно показав пользователю окно сообщения, после того, как завершится исполнение раскадровки. Для этого нам понадобится обработать событие раскадровки Completed, которое вызывается при её завершении. В итоге мы пришли к такому коду файла MyControl.xaml.cs, Листинг 13.4

using System;
using System.Windows;
using System.Windows.Controls;

namespace P3_1
{
    public partial class MyControl : UserControl
    {
        public event EventHandler ReadyToLoadPage;

        public string Message
        {
            get;
            set;
        }
        
        public MyControl()
        {
            InitializeComponent();
        }

        private void LayoutRoot_DoubleTap(object sender, System.Windows.Input.GestureEventArgs e)
        {
            ProgressStoryboard.Begin();
        }

        private void ProgressStoryboard_Completed(object sender, EventArgs e)
        {
            if (Message!=null) 
                MessageBox.Show(Message);
            ReadyToLoadEventCall();
        }

        private void ReadyToLoadEventCall()
        {
            if (this.ReadyToLoadPage != null)
                this.ReadyToLoadPage(new object(), new EventArgs());
        }
    }
}

Здесь мы, при обработке события завершения раскадровки ProgressStoryboard_Completed проверяем, задано ли свойство Message. Если задано – выводим сообщение. Приложение ожидает реакции пользователя на сообщение, когда пользователь отреагировал, вызывается метод ReadyToLoadEventCall. В этом методе мы проверяем, подключён ли обработчик события, и если это так – вызываем событие. При обработке события нам важно то, что оно произойдёт, поэтому передача параметров носит формальный характер.

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

Добавим в проект еще одну страницу (контекстное меню проекта, команда Добавить > Создать элемент > Страница Windows Phone в книжной ориентации, дадим ей имя NextPage.xaml).

На странице MainPage.xaml мы можем, во-первых, задать свойство элемента управления Message, запишем туда текст "Теперь можно продолжать!". Это свойство, как и при работе с обычными элементами управления, доступно в панели свойств. При группировке свойств по категориям оно будет находиться в категории Разное. Так же, зададим обработчик события ReadyToLoadPage (рис. 13.8.), оно будет перечислено среди прочих событий элемента управления, которые мы можем обрабатывать на странице приложения, для создания обработчика достаточно выполнить двойной щелчок по соответствующему полю.

(рис 13.8) Настройка пользовательского элемента управления на странице

В Листинге 13.5 приведен XAML-код страницы MainPage.xaml

<phone:PhoneApplicationPage
    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"
    xmlns:local="clr-namespace:P3_1"
    x:Class="P3_1.MainPage"
    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">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>

        
        <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
            <TextBlock Text="ПОЛЬЗОВАТЕЛЬСКИЕ ЭЛЕМЕНТЫ УПРАВЛЕНИЯ" 
Style="{StaticResource PhoneTextNormalStyle}" Margin="12,0"/>
            <TextBlock Text="пример" Margin="9,-7,0,0" 
Style="{StaticResource PhoneTextTitle1Style}"/>
        </StackPanel>

        <!--ContentPanel — поместите здесь дополнительное содержимое-->
        <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">

            <local:MyControl x:Name="MyControlMainPage" HorizontalAlignment="Left" 
Margin="51,128,0,0" VerticalAlignment="Top" 
ReadyToLoadPage="MyControlMainPage_ReadyToLoadPage" Message="Теперь можно продолжать!"/>

        </Grid>

    </Grid>

</phone:PhoneApplicationPage>

В обработчик события ReadyToLoadPage достаточно добавить команду перехода на нужную страницу.

В итоге код файла MainPage.xaml.cs будет выглядеть так, как показано в Листинге 13.6.

using System;
using System.Windows.Navigation;
using Microsoft.Phone.Controls;

namespace P3_1
{
    public partial class MainPage : PhoneApplicationPage
    {
        // Конструктор
        public MainPage()
        {
            InitializeComponent();
        }

        private void MyControlMainPage_ReadyToLoadPage(object sender, EventArgs e)
        {
            NavigationService.Navigate(new Uri("/NextPage.xaml", UriKind.Relative));
        }

    }
}

Выводы

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

Задание

Создайте проект приложения, добавьте в него пользовательский элемент управления, содержащий анимацию, которая запускается при касании этого элемента управления. Добавьте элемент управления на страницу MainPage.xaml и разместите на ней анимированную с помощью раскадровки геометрическую фигуру. Настройте поведение приложения так, чтобы раскадровка, описанная на странице MainPage.xaml запускалась после завершения раскадровки, описанной в пользовательском элементе управления.

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

К данной лекции подготовлено видеоприложение и демонстрационный программный проект.

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