Статьи

Windows Phone 8: кратко: пользовательский интерфейс

XAML — это аббревиатура от расширяемого языка разметки приложений. Это язык разметки, основанный на XML, и его назначение и философия очень похожи на HTML. Каждый элемент управления, который может быть размещен на странице, будь то кнопка, текстовое поле или пользовательские элементы управления, идентифицируется определенным тегом XML. Как и XML, структура является иерархической; Вы можете разместить теги внутри других тегов. Например, эта иерархическая структура позволяет определять макет страницы благодаря некоторым элементам управления, которые действуют как контейнер для других элементов управления, таких как Grid или StackPanel .

Ниже приведен пример XAML, который определяет страницу Windows Phone:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<phone:PhoneApplicationPage
    x:Class=»FirstApp.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=»True»>
 
    <Grid x:Name=»LayoutRoot» Background=»Transparent»>
        <Grid.RowDefinitions>
            <RowDefinition Height=»Auto»/>
            <RowDefinition Height=»*»/>
        </Grid.RowDefinitions>
 
        <Grid x:Name=»ContentPanel» Grid.Row=»1″ Margin=»12,0,12,0″>
            <StackPanel>
                <TextBlock Text=»This is a page» />
            </StackPanel>
        </Grid>
    </Grid>
</phone:PhoneApplicationPage>

PhoneApplicationPage — это базовый класс страницы Windows Phone. Как видите, все остальные элементы управления находятся внутри него. Обратите внимание также на атрибут x:Class ; он идентифицирует, какой класс code-behind связан с этой страницей. В этом примере код, который может взаимодействовать со страницей, будет храниться в классе MainPage который является частью пространства имен FirstApp . Мы можем увидеть этот класс, просто нажав на черную стрелку рядом с файлом XAML в Solution Explorer. Вы увидите другой файл с тем же именем, что и XAML, плюс расширение .cs .

Визуальное представление страницы

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

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

По умолчанию Visual Studio назначает пространства имен, используя ту же структуру папок проекта. Это означает, что, например, если у вас есть класс с именем MyClass хранящийся в файле в папке Classes , по умолчанию полное пространство имен вашего класса будет Classes.MyClass .

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

1
xmlns:phone=»clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone»

Каждое пространство имен начинается с префикса xmlns , который является стандартным пространством имен XML, за которым следует пользовательский префикс (в данном примере это phone ). Этот префикс очень важен, потому что он будет использоваться на остальной части страницы для добавления элементов управления. Затем мы определяем полное пространство имен, которое содержит элементы управления. Если класс является частью нашего проекта, достаточно указать только пространство имен; в противном случае нам также нужно определить, какая сборка (то есть имя DLL) содержит класс.

В предыдущем примере мы хотим включить элементы управления и ресурсы на нашей странице, которые определены в пространстве имен Microsoft.Phone.Controls , которое включено в библиотеку Microsoft.Phone.dll .

Класс PhoneApplicationPage дает вам пример того, как использовать пространство имен. Поскольку класс PhoneApplicationPage является частью пространства имен Microsoft.Phone.Controls , мы должны добавить префикс phone к тегу, чтобы использовать его:

1
<phone:PhoneApplicationPage />

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

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

Свойства используются для изменения внешнего вида или поведения элемента управления. Обычно свойство просто устанавливается путем присвоения значения определенному атрибуту. Например, если мы хотим присвоить значение свойству Text элемента управления TextBlock , мы можем сделать это следующим образом:

1
<TextBlock Text=»This is a text block» />

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

1
2
3
4
5
<Grid>
    <Grid.Background>
        <ImageBrush ImageSource=»/Assets/Background.png» />
    </Grid.Background>
</Grid>

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

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

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

1
<Button Tap=»OnButtonClicked» />

Когда вы определяете действие, Visual Studio автоматически предложит вам создать обработчик событий , который является методом (объявленным в коде), который выполняется при запуске события.

1
2
3
4
private void OnButtonClicked(object sender, GestureEventArgs e)
{
    MessageBox.Show(«Hello world»);
}

В предыдущем примере мы показываем классическое сообщение «Hello world» пользователям, когда кнопка нажата.

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

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

Ресурсы страницы определены на одной странице и доступны всем элементам управления, которые являются частью этой страницы. Они помещаются в определенное свойство, которое называется Resources класса PhoneApplicationPage .

1
2
3
<phone:PhoneApplicationPage.Resources>
    <!— you can place resources here —>
</phone:PhoneApplicationPage.Resources>

Ресурсы приложения , напротив, доступны по всему миру, и их можно использовать на любой странице приложения. Они определены в файле App.xaml , и стандартный шаблон уже содержит необходимое определение.

1
2
3
<Application.Resources>
    <!— here you can place global resources —>
</Application.Resources>

Каждый ресурс однозначно идентифицируется именем, которое назначается с помощью свойства x:Key . Чтобы применить ресурс к элементу управления, нам нужно ввести понятие расширений разметки . Это специальные расширения, которые позволяют нам применять различные варианты поведения, которые в противном случае потребовали бы некоторого кода для нормальной работы. В мире XAML существует множество расширений разметки, и одно из них, необходимое для применения ресурса, называется StaticResource . Вот пример того, как его использовать:

1
<TextBlock Text=»MY APPLICATION» Style=»{StaticResource PhoneTextNormalStyle}» />

В этом примере ресурс применяется к свойству Style путем включения ключевого слова StaticResource в фигурные скобки, за которым следует имя ресурса, которое является значением свойства x:Key .

Ресурсы также могут быть определены во внешнем файле с именем ResourceDictionary если вы хотите лучше организовать свой проект. Для этого щелкните правой кнопкой мыши свой проект в Visual Studio, нажмите « Добавить» > « Новый элемент» и выберите файл XML . Дайте файлу имя, которое заканчивается расширением .xaml, и включите следующее определение:

1
2
3
4
5
6
7
<ResourceDictionary
    xmlns=»http://schemas.microsoft.com/winfx/2006/xaml/presentation»
    xmlns:x=»http://schemas.microsoft.com/winfx/2006/xaml»>
     
    <!— put resources here —>
     
</ResourceDictionary>

Теперь вы можете добавить его в свой проект, объявив его в App.xaml :

1
2
3
4
5
6
7
<Application.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source=»Assets/Resources/Styles.xaml» />
        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
</Application.Resources>

Обратите внимание на свойство MergedDictionaries : здесь должны быть объявлены все файлы внешних ресурсов. Таким образом, они будут автоматически объединены, и каждый ресурс, объявленный в каждом внешнем файле, будет доступен для каждой страницы, как если бы они были объявлены встроенными.

Давайте теперь посмотрим подробно, какие ресурсы являются наиболее важными.

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

1
2
3
4
<Style x:Key=»CustomText» TargetType=»TextBlock»>
    <Setter Property=»FontSize» Value=»24″ />
    <Setter Property=»FontWeight» Value=»Bold» />
</Style>

Стиль определяется тегом Style , который имеет два важных атрибута: x:Key , имя стиля и TargetType , тип элементов управления, который подходит для этого стиля.

Внутри тега Style вы можете разместить столько тегов Setter сколько захотите. Каждый идентифицирует свойство элемента управления, которое вы хотите изменить. Каждый тег Setter нуждается в двух атрибутах: Property — это свойство элемента управления, которое вы хотите изменить, и Value — это значение, которое вы хотите присвоить свойству.

Стиль, определенный в предыдущем примере, можно применить к любому TextBlock управления TextBlock . Его цель — изменить размер шрифта до 24 и применить жирный стиль к тексту.

Существуют также специальные типы стилей, называемые неявными стилями . Они определяются так же, как и стили в предыдущем примере, за исключением того, что отсутствует атрибут x:Key . В этом случае стиль автоматически применяется к каждому TargetType управления, который соответствует значению свойства TargetType , в соответствии с областью, в которой был определен стиль. Если стиль установлен как ресурс страницы, он будет применяться только к элементам управления страницы; если стиль установлен как ресурс приложения, он будет применяться ко всем элементам управления в приложении.

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

В следующем примере показан шаблон данных:

1
2
3
4
5
6
7
8
<DataTemplate x:Key=»PeopleTemplate»>
    <StackPanel>
        <TextBlock Text=»Name» />
        <TextBlock Text=»{Binding Path=Name}» />
        <TextBlock Text=»Surname» />
        <TextBlock Text=»{Binding Path=Surname}» />
    </StackPanel>
</DataTemplate>

Шаблон данных просто содержит XAML, который будет использоваться для визуализации определенного элемента. Если, например, мы применим этот шаблон данных к свойству ItemTemplate элемента управления ListBox , результатом будет повторение определенного XAML для каждого элемента в коллекции (на данный момент просто игнорируем расширение разметки Binding ; мы Я буду иметь дело с этим позже, когда мы поговорим о привязке данных).

Как и для любого другого ресурса, шаблоны данных могут быть назначены свойству с помощью расширения разметки StaticResource .

1
<ListBox ItemTemplate=»{StaticResource PeopleTemplate}» />

XAML — мощный язык, потому что он позволяет нам делать больше, чем просто создавать макет приложений. Одной из наиболее интересных функций является функция анимации, которую можно создать с помощью Storyboard управления « Storyboard .

Элемент управления Storyboard может использоваться для определения различных типов анимации:

  • DoubleAnimation , которая может использоваться для изменения числового значения свойства (например, Width или FontSize ).
  • ColorAnimation , которая может использоваться для взаимодействия со свойствами, которые определяют цвет (как внутри SolidColorBrush ).
  • PointAnimation , которую можно применять к свойствам, которые определяют координату точки.

Следующий пример кода определяет анимацию:

1
2
3
4
5
6
7
<Storyboard x:Name=»Animation»>
    <DoubleAnimation Storyboard.TargetName=»RectangleElement»
                     Storyboard.TargetProperty=»Width»
                     From=»200″
                     To=»400″
                     Duration=»00:00:04″ />
</Storyboard>

Первые два свойства унаследованы от Storyboard управления Storyboard : Storyboard.TargetName используется для задания имени элемента управления, который мы собираемся анимировать, а Storyboard.TargetProperty — это свойство, значение которого мы собираемся изменить во время анимации.

Далее мы определяем поведение анимации: начальное значение (свойство From ), конечное значение (свойство To ) и продолжительность (свойство Duration ). Поведение, определенное в предыдущем примере, анимирует элемент управления Rectangle , увеличив его ширину с 200 до 400 в течение 4 секунд.

Мы также можем более глубоко контролировать анимацию, используя вариант UsingKeyFrames доступный для каждого типа анимации:

1
2
3
4
5
6
7
8
<Storyboard x:Name=»Animation»>
    <DoubleAnimationUsingKeyFrames Storyboard.TargetName=»RectangleElement»
                                   Storyboard.TargetProperty=»Width»>
        <LinearDoubleKeyFrame KeyTime=»00:00:00″ Value=»200″ />
        <LinearDoubleKeyFrame KeyTime=»00:00:02″ Value=»250″ />
        <LinearDoubleKeyFrame KeyTime=»00:00:04″ Value=»500″ />
    </DoubleAnimationUsingKeyFrames>
</Storyboard>

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

В предыдущем примере в качестве значения Width элемента управления « Rectangle задано значение 200. Затем через две секунды оно увеличивается до 250, а через четыре секунды устанавливается на 500.

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

Чтобы добавить функцию замедления, вам просто нужно установить свойство анимации EasingFunction , как показано в следующем примере:

1
2
3
4
5
6
7
8
9
<Storyboard x:Name=»EasingAnimation»>
    <PointAnimation From=»0,0″ To=»0, 200″ Duration=»00:00:3″
                                    Storyboard.TargetName=»Circle»
                                    Storyboard.TargetProperty=»Center»>
        <PointAnimation.EasingFunction>
            <BounceEase Bounces=»2″ EasingMode=»EaseOut» />
        </PointAnimation.EasingFunction>
    </PointAnimation>
</Storyboard>

После того как вы определили обычную анимацию (в данном примере это PointAnimation которая перемещает объект Ellipse из координат (0, 0) в (0, 200)), вы можете установить свойство EasingFunction с помощью одной из доступных функций замедления. , В этом примере показано, как использовать функцию BounceEase , которую можно использовать для применения эффекта отскакивания к объекту (количество отскоков выполняется с Bounces свойства Bounces ).

Другие доступные функции ослабления:

  • BackEase , который немного убирает движение анимации до ее запуска.
  • CircleEase , который применяет круговую функцию к анимации ускорения.
  • ElasticEase , который создает анимацию, напоминающую колеблющуюся пружину.

Официальная документация MSDN содержит полный список доступных функций замедления.

Анимации рассматриваются как ресурсы. Они могут быть определены как локальные ресурсы, ресурсы страницы или ресурсы приложения. В отличие от традиционных ресурсов, элементы управления Storyboard идентифицируются свойством x:Name , как обычный элемент управления.

В следующем примере показана анимация, заданная как ресурс страницы:

1
2
3
4
5
6
7
8
9
<phone:PhoneApplicationPage.Resources>
    <Storyboard x:Name=»Animation»>
        <DoubleAnimation Storyboard.TargetName=»RectangleElement»
                    Storyboard.TargetProperty=»Width»
                    From=»200″
                    To=»400″
                    Duration=»00:00:04″ />
    </Storyboard>
</phone:PhoneApplicationPage.Resources>

Благодаря уникальному идентификатору вы сможете управлять анимацией в коде. Каждый объект Storyboard предлагает множество методов для управления им, таких как Begin() , Stop() или Resume() . В следующем коде вы видите обработчики событий, назначенные двум кнопкам, которые используются для запуска и остановки анимации:

1
2
3
4
5
6
7
8
9
private void OnStartClicked(object sender, GestureEventArgs e)
{
    Animation.Begin();
}
 
private void OnStopClicked(object sender, GestureEventArgs e)
{
    Animation.Stop();
}

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

Когда вы создаете канал связи, используя привязку данных, вы определяете source (который содержит данные для отображения) и target (который заботится об отображении значения). По умолчанию канал привязки установлен в режим OneWay . Это означает, что при изменении source target обновляется для отображения нового значения, а не наоборот. Если нам нужно создать двусторонний канал связи (например, поскольку целью является элемент управления TextBox и нам нужно перехватить новое значение, вставленное пользователем), мы можем установить свойство Mode привязки в TwoWay .

1
<TextBox Text=»{Binding Path=Name, Mode=TwoWay}» />

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

В следующем примере показано, как привязка данных может использоваться для создания канала между двумя элементами управления XAML:

1
2
3
4
<StackPanel>
    <Slider x:Name=»Volume» />
    <TextBlock x:Name=»SliderValue» Text=»{Binding ElementName=Volume, Path=Value}» />
</StackPanel>

Первое, на что нужно обратить внимание, это то, что для применения привязки нам нужно использовать другое расширение разметки , называемое Binding . С помощью этого выражения мы соединяем свойство Text элемента управления TextBlock (цель) со свойством Value элемента управления Slider с именем Volume (источник).

Поскольку и Text и Value являются зависимыми свойствами, при каждом перемещении ползунка выбранное значение будет автоматически отображаться на экране в элементе управления TextBlock .

Одной из самых мощных функций привязки данных является возможность связывать элементы управления с объектами, которые являются частью вашего кода. Однако, во-первых, нам нужно представить концепцию DataContext . DataContext — это свойство, которое доступно почти для каждого элемента управления и может использоваться для определения его связующего контекста, который также автоматически наследуется каждым вложенным элементом управления. Когда вы определяете объект как DataContext , элемент управления и все его дочерние элементы будут иметь доступ ко всем его свойствам.

Давайте рассмотрим пример, который поможет вам лучше понять, как это работает. Допустим, у вас есть класс, который представляет человека:

1
2
3
4
5
public class Person
{
    public string Name { get;
    public string Surname { get;
}

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

1
2
3
4
5
6
7
8
public MainPage()
{
    InitializeComponent();
    Person person = new Person();
    person.Name = «Matteo»;
    person.Surname = «Pagani»;
    Author.DataContext = person;
}

Когда страница инициализируется, мы создаем новый объект Person и устанавливаем значение для свойств Name и Surname . Затем мы устанавливаем этот новый объект как DataContext элемента управления Author . Давайте посмотрим на странице XAML элемент управления Author и то, как отображаются свойства Name и Surname :

1
2
3
4
5
6
<StackPanel x:Name=»Author»>
    <TextBlock Text=»Name» />
    <TextBlock Text=»{Binding Path=Name}» />
    <TextBlock Text=»Surname» />
    <TextBlock Text=»{Binding Path=Surname}» />
</StackPanel>

Author — это имя, назначенное StackPanel управления StackPanel , который является контейнером, который мы поместили в различные элементы управления TextBlock . В предыдущем примере мы снова видим расширение разметки Binding в действии, на этот раз с другим атрибутом: Path . Мы используем его, чтобы сообщить XAML, какое свойство текущего DataContext отображать. Поскольку DataContext наследуется от StackPanel управления StackPanel , каждый TextBlock имеет доступ к свойствам объекта Person мы создали в коде позади. Обратите внимание, что атрибут Path является необязательным. Два следующих утверждения абсолютно одинаковы:

1
2
<TextBlock Text=»{Binding Path=Name}» />
<TextBlock Text=»{Binding Name}» />

Предыдущий код имеет недостаток. Все работает нормально, но если вы измените значение одного из свойств Name или Surname во время выполнения, пользовательский интерфейс не будет обновлен для отображения нового значения. Причина в том, что Name и Surname являются простыми свойствами, поэтому они не могут уведомить пользовательский интерфейс о том, что что-то изменилось, в отличие от свойств зависимости. Для этого сценария платформа XAML представила интерфейс INotifyPropertyChanged который может быть реализован объектами, которые должны удовлетворять этому требованию уведомления. Вот как класс Person может быть изменен для реализации этого интерфейса:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public class Person: INotifyPropertyChanged
{
    private string _name;
    private string _surname;
 
    public string Name
    {
        get { return _name;
        set
        {
            _name = value;
            OnPropertyChanged();
        }
    }
 
 
    public string Surname
    {
        get { return _surname;
        set
        {
            _surname = value;
            OnPropertyChanged();
        }
    }
 
    public event PropertyChangedEventHandler PropertyChanged;
 
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }
}

Класс теперь реализует интерфейс INotifyPropertyChanged , что позволяет нам поддерживать обработчик событий (называемый PropertyChangedEventHandler ), который запускается каждый раз, когда изменяется значение свойства. Класс также реализует метод OnPropertyChanged() который действует как оболочка обработчика событий и должен вызываться при изменении свойства.

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

Связывание данных особенно полезно, когда вам приходится иметь дело с коллекциями объектов, такими как массивы или списки (в основном, с типами коллекций каждой платформы, которые реализуют интерфейс IEnumerable ). Почти каждый элемент управления, который поддерживает коллекции, которые наследуются от класса ItemsControl (например, ListBox или LongListSelector ), имеет свойство ItemsSource , которое может быть непосредственно назначено списку.

Вы можете контролировать, как каждый объект коллекции будет отображаться, используя свойство ItemTemplate . Как мы уже видели, когда говорили о шаблонах данных, это свойство позволяет нам указать, какой XAML использовать для отображения объекта.

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

1
2
3
4
5
6
7
8
<DataTemplate x:Key=»PeopleTemplate»>
    <StackPanel>
        <TextBlock Text=»Name» />
        <TextBlock Text=»{Binding Path=Name}» />
        <TextBlock Text=»Surname» />
        <TextBlock Text=»{Binding Path=Surname}» />
    </StackPanel>
</DataTemplate>

Когда вы устанавливаете коллекцию как ItemSource , каждый объект, который является ее частью, становится DataContext ItemTemplate . Если, например, свойство ItemsSource объекта ListBox связано с коллекцией, тип которой — List<Person> , элементы управления, включенные в ItemTemplate , смогут получить доступ ко всем свойствам класса Person .

Это реальное значение предыдущего примера кода: для каждого объекта Person , являющегося частью коллекции, мы собираемся отобразить значения свойств Name и Surname .

Другая важная часть головоломки при работе с коллекциями — это класс ObservableCollection<T> . Он действует как обычная коллекция, поэтому вы можете легко добавлять, удалять и перемещать объекты. Под капотом он реализует интерфейс INotifyPropertyChanged так что каждый раз, когда коллекция изменяется, пользовательский интерфейс получает уведомление. Таким образом, каждый раз, когда мы манипулируем коллекцией (например, добавляем новый элемент), связанный с ним элемент управления будет автоматически обновляться для отражения изменений.

Конвертеры играют важную роль в привязке данных. Иногда, на самом деле, вам нужно изменить исходные данные, прежде чем они будут отправлены в цель. Типичным примером является случай, когда вам приходится иметь дело со свойствами DateTime . Класс DateTime содержит полное представление даты, включая часы, минуты, секунды и миллисекунды. Однако в большинстве случаев вам не нужно отображать полное представление — часто просто достаточно даты.

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

Чтобы создать конвертер, вам нужно добавить новый класс в ваш проект (щелкните правой кнопкой мыши в Visual Studio, выберите « Добавить» > « Класс» ), и он должен наследоваться от интерфейса IValueConverter . Ниже приведен пример конвертера:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
public class DateTimeConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value != null)
        {
            DateTime date = (DateTime)value;
            return date.ToShortDateString();
        }
        return string.Empty;
    }
 
    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value != null)
        {
            DateTime date = DateTime.Parse(value.ToString());
            return date;
        }
        return DateTime.Now;
    }
}

Когда вы поддерживаете интерфейс IValueConverter , вы вынуждены реализовать два метода:

  • Convert() — это метод, который вызывается при отправке данных из источника в цель.
  • ConvertBack() делает обратное — он вызывается, когда данные из цели отправляются обратно в источник.

В большинстве случаев достаточно реализовать метод Convert() который поддерживается каждой привязкой. ConvertBack() метод ConvertBack() поддерживается только при TwoWay привязки TwoWay .

Оба метода получают важную информацию в качестве входных параметров:

  • Значение, возвращаемое из источника привязки (которым нужно манипулировать).
  • Свойство, к которому была применена привязка.
  • Необязательный параметр, который можно установить в XAML с помощью свойства ConverterParameter . Этот параметр можно использовать для применения другого поведения в логике преобразователя.
  • Текущая культура.

Предыдущий пример кода показывает пример DateTime упомянутый ранее. В методе Convert() мы получаем исходное значение и после того, как мы преобразовали его в объект DateTime , мы возвращаем строку с коротким форматированием.

В ConvertBack() мы получаем строку, возвращаемую из ConvertBack() управления, и преобразуем ее в объект DateTime перед отправкой обратно в код.

Конвертеры обрабатываются как ресурсы — их нужно объявить и включить в выражение привязки с помощью ключевого слова StaticResource .

1
2
3
4
<phone:PhoneApplicationPage.Resources>
    <converters:DateTimeConverter x:Key=»DateConverter» />
</phone:PhoneApplicationPage.Resources>
<TextBlock Text=»{Binding Path=BirthDate, Converter={StaticResource DateConverter}}» />

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

Windows Phone 8 SDK включает в себя множество встроенных элементов управления, которые можно использовать для определения пользовательского интерфейса приложения. Существует так много элементов управления, что практически невозможно проанализировать все из них в этой серии, поэтому мы подробнее рассмотрим только самые важные из них.

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

StackPanel управления StackPanel можно использовать для простого выравнивания вложенных элементов управления один под другим. Он может автоматически адаптироваться к размеру дочерних элементов управления.

1
2
3
4
<StackPanel>
    <TextBlock Text=»First text» />
    <TextBlock Text=»Second text» />
</StackPanel>

Вы также можете использовать StackPanel управления StackPanel для выравнивания элементов управления по горизонтали, один рядом с другим, установив для свойства Orientation значение Horizontal .

1
2
3
4
<StackPanel Orientation=»Horizontal»>
    <TextBlock Text=»First text» />
    <TextBlock Text=»Second text» />
</StackPanel>

Элемент управления StackPanel

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

01
02
03
04
05
06
07
08
09
10
11
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height=»50″ />
        <RowDefinition MaxHeight=»100″ />
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width=»200″ />
        <ColumnDefinition Width=»*» />
    </Grid.ColumnDefinitions>
    <TextBlock Text=»1° row — 2° column» Grid.Row=»0″ Grid.Column=»1″ />
</Grid>

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

Чтобы определить положение элемента управления внутри сетки, мы будем использовать два прикрепленных свойства, которые являются специальными свойствами зависимостей, которые наследуются от Grid управления Grid и могут использоваться с каждым элементом управления. С Grid.Row свойства Grid.Row мы можем установить номер строки, а с помощью Grid.Column мы можем установить номер столбца.

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

Grid Control

ScrollViewer управления ScrollViewer является контейнером, но он не определяет макет. Если вы хотите организовать вложенные элементы управления, вам все равно придется использовать другой контейнер, например, StackPanel или Grid . Целью этого элемента управления является создание макета, который больше, чем размер экрана. Таким образом, пользователи смогут прокрутить вниз, чтобы увидеть остальную часть пользовательского интерфейса.

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

1
2
3
4
5
<ScrollViewer>
    <StackPanel>
        <TextBlock TextWrapping=»Wrap» Text=»This can be long text» />
    </StackPanel>
</ScrollViewer>

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

В следующем примере показано, как обернуть изображение внутри красной рамки:

1
2
3
<Border BorderThickness=»5″ BorderBrush=»Red»>
    <Image Source=»/Assets/windows-phone-8-logo.png»/>
</Border>
Пограничный контроль используется для встраивания изображения

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

1
2
3
<Border BorderThickness=»5, 10, 15, 20″ BorderBrush=»Red»>
    <Image Source=»/Assets/windows-phone-8-logo.png»/>
</Border>
Пограничный контроль с открытой границей

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

Еще одно полезное свойство Padding, которое можно использовать для указания расстояния между границей и дочерним элементом управления, как показано в следующем примере:

1
2
3
<Border BorderThickness="5" BorderBrush="Red" Padding="10">
    <Image Source="/Assets/windows-phone-8-logo.png"/>
</Border>
Пограничный контроль с отступами

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

TextBlockявляется одним из основных элементов управления XAML и используется для отображения текста на экране. Его самое важное свойство Text, которое, конечно, содержит текст для отображения. У вас есть много свойств для выбора внешнего вида текста, таких как FontSize, FontWeightи FontStyle, и вы можете автоматически переносить текст в несколько строк в случае, если текст слишком длинный, установив TextWrappingсвойство в true.

1
<TextBlock Text="This is long and bold text" TextWrapping="Wrap" FontWeight="Bold" />

Вы также можете применить другое форматирование к тексту, не используя несколько TextBlockэлементов управления, используя Runтег, который можно использовать для разделения текста, как показано в следующем примере:

1
2
3
4
5
<TextBlock>
    <Run Text="Standard text" />
    <LineBreak />
    <Run Text="Bold test" FontWeight="Bold" />
</TextBlock>

Элемент RichTextBlockуправления похож на TextBlock, но он предлагает больше контроля над стилями форматирования, которые могут быть применены к тексту. Как и в HTML, вы можете определять абзацы, применять различные стили текста и многое другое.

1
2
3
4
5
6
7
8
9
<RichTextBox>
    <Paragraph>
        <Bold>This is a paragraph in bold</Bold>
    </Paragraph>
    <Paragraph>
        <Italic>This is a paragraph in italics</Italic>
        <LineBreak />
    </Paragraph>
</RichTextBox>

Элемент Imageуправления может быть использован для отображения изображений. Вы можете установить Sourceсвойство с удаленным путем (URL-адрес изображения, опубликованный в Интернете) или локальным путем (файл, который является частью вашего проекта Visual Studio). Вы не можете назначить путь, который ссылается на изображение, хранящееся в локальном хранилище приложения. Позже в этой серии мы увидим, как справиться с этим ограничением.

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

  • Uniform: Значение по умолчанию. Размер изображения изменяется в соответствии с размером контейнера, сохраняя исходное соотношение сторон, чтобы изображение не выглядело искаженным. Если форматное соотношение контейнера отличается от изображения, изображение будет выглядеть меньше доступного пространства.
  • Fill: Изображение изменяется в соответствии с размером контейнера, игнорируя соотношение сторон. Он заполнит все доступное пространство, но если размер элемента управления не имеет такое же соотношение сторон, как у изображения, он будет выглядеть искаженным.
  • UniformToFillпредставляет собой смесь предыдущих значений. Если изображение имеет другое соотношение сторон, чем у контейнера, изображение обрезается, чтобы оно могло сохранить правильное соотношение сторон и в то же время заполнить все доступное пространство.
  • None : Изображение отображается в оригинальном размере.

Эти элементы управления используются для получения информации от пользователей.

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

Например, вы можете отобразить цифровую клавиатуру, если пользователям нужно только ввести число; или вы можете использовать клавиатуру электронной почты (которая обеспечивает легкий доступ к символам, таким как @), если вы собираете адрес электронной почты.

Вы можете контролировать тип клавиатуры с помощью InputScopeсвойства. Список поддерживаемых значений очень длинный и его можно найти в документации MSDN . Некоторые из наиболее используемых:

  • Text для общего ввода текста с поддержкой словаря.
  • Number для ввода общего числа.
  • TelephoneNumber для ввода конкретного телефонного номера (это та же клавиатура, которая отображается при составлении номера в собственном приложении Phone).
  • EmailNameOrAddress который добавляет быстрый доступ к символам, таким как @.
  • Url который добавляет быстрый доступ к общим доменам, таким как .com или .it (в зависимости от языка клавиатуры).
  • Search который предоставляет автоматические предложения.
1
<TextBox InputScope="TelephoneNumber" />

Совет: если элемент управления TextBox используется для сбора общего текста, всегда не забывайте устанавливать для свойства InputScope значение Text. Таким образом, пользователи получат поддержку от инструментов автозаполнения и автокоррекции.

Слева направо Текстовые области ввода EmailNameOrAddress и PhoneNumber

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

Одна из целей разработчика должна состоять в том, чтобы пользовательский интерфейс ее или его приложения был как можно более совместимым с рекомендациями операционной системы. Чтобы помочь в достижении этой цели, SDK предлагает множество готовых ресурсов, которые можно применять к элементам управления, чтобы получить тот же внешний вид и функции, что и собственные приложения. Эти стили обычно используются с такими элементами управления, как TextBox, TextBlockили RadioButton, и они предоставляют стандартный набор визуальных функций (таких как размер шрифта, цвет, прозрачность и т. Д.), Которые согласуются с другими приложениями.

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

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

1
<TextBlock Text="App name" Style="{StaticResource PhoneTextNormalStyle}" />

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

Текст для отображения задается с помощью Contentсвойства, как в следующем примере:

1
<Button Content="Tap me" Tap="OnClickMeClicked" />

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

1
2
3
4
5
6
7
<Button Tap="OnClickMeClicked">
    <Button.Content>
        <StackPanel>
            <Image Source="/Assets/logo.png" Height="200" />
        </StackPanel>
    </Button.Content>
</Button>

Эти элементы управления предлагают много способов взаимодействия с пользователями. Наиболее распространенные события Click, Tapи DoubleTap.

Примечание. Нажатие и касание — это одно и то же событие — они оба запускаются, когда пользователи нажимают элемент управления. Tap был введен в Windows Phone 7.5 для большей совместимости с сенсорным интерфейсом, но во избежание взлома старых приложений событие Click по-прежнему поддерживается.

Большинство элементов управления, которые мы видели до сих пор, являются частью инфраструктуры XAML и доступны для любых других технологий на основе XAML, таких как приложения Silverlight, WPF и Windows Store.

Однако есть некоторые элементы управления, которые доступны только на платформе Windows Phone, поскольку они предназначены для мобильных устройств. Давайте посмотрим на них.

Элемент Panoramaуправления часто используется в приложениях Windows Phone, поскольку он обычно рассматривается как отправная точка. Элемент управления получает свое имя, потому что увеличенное изображение используется в качестве фона страницы. Пользователи могут проводить пальцем влево или вправо, чтобы увидеть другие доступные страницы. Поскольку изображение больше размера страницы, телефон применяет эффект параллакса, который визуально приятен для пользователей.

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

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

С точки зрения разработчика, элемент Panoramaуправления состоит из разных страниц: каждая из них является PanoramaItemэлементом управления, который содержит макет страницы.

PanoramaМожет иметь родовое название, как название приложения (которое присвоенная Titleсобственность), в то время как каждая страница может иметь свой собственный специфический заголовок (который назначен на Headerимущество).

01
02
03
04
05
06
07
08
09
10
11
12
<phone:Panorama Title="Panorama">
    <phone:PanoramaItem Header="First page">
        <StackPanel>
            <TextBlock Text="Page 1" />
        </StackPanel>
    </phone:PanoramaItem>
    <phone:PanoramaItem Header="Second page">
        <StackPanel>
            <TextBlock Text="Page 2" />
        </StackPanel>
    </phone:PanoramaItem>
</phone:Panorama>

Примечание. Элемент управления Panorama (например, элемент управления Pivot) не доступен по умолчанию на странице. Вам придется объявить следующее пространство имен:

1
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"

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

Сводный контроль

Тем не менее, Pivotэлемент управления используется в целях, не разделяемых элементом Panoramaуправления:

  • Для отображения одного вида информации применяется к различным контекстам. Предыдущая цифра является хорошим примером. Информация на каждой странице одинакова (прогноз погоды), но упоминается в разных контекстах (городах).
  • Для отображения различных видов информации, которые относятся к одному и тому же контексту. Хорошей тому пример является страница с информацией о контактах в People Hub на Windows Phone — у вас много информации (контакт, обновления в социальных сетях, разговоры и т. Д.), Но все это относится к одному контексту (контакту) ,

Как и предполагалось ранее, XAML для элемента Pivotуправления работает так же, как XAML для элемента Panoramaуправления. Вызывается основной элемент управления Pivot, а вызываются вложенные элементы управления, представляющие страницы PivotItem.

01
02
03
04
05
06
07
08
09
10
11
12
<phone:Pivot Title="Pivot">
    <phone:PivotItem Header="First page">
        <StackPanel>
            <TextBlock Text="Page 1" />
        </StackPanel>
    </phone:PivotItem>
    <phone:PivotItem Header="Second page">
        <StackPanel>
            <TextBlock Text="Page 2"/>
        </StackPanel>
    </phone:PivotItem>
</phone:Pivot>

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

Вы можете добавить два типа элементов на панель приложения:

  • Иконки всегда отображаются (если они ApplicationBarне свернуты), и одновременно может отображаться до четырех.
  • Пункты меню — это просто текстовые элементы, которые отображаются только при открытой панели приложения. Там нет ограничений на количество предметов, которые могут быть включены.
Открытая панель приложений

ApplicationBarНе ведет себя , как и другие элементы управления XAML. Он не является частью страницы — на самом деле он объявлен вне основного Grid, называемого LayoutRoot— и не наследуется от FrameworkElementкласса, как любой другой элемент управления. Самым большим недостатком этого является то, что элемент управления не поддерживает привязку; вам придется полагаться на сторонние библиотеки, например на реализацию, доступную в Cimbalino Toolkit для Windows Phone .

Вот ApplicationBarобразец:

1
2
3
4
5
6
7
8
<phone:PhoneApplicationPage.ApplicationBar>
    <shell:ApplicationBar IsVisible="True" IsMenuEnabled="True">
        <shell:ApplicationBarIconButton IconUri="/Assets/Add.png" Text="Add" Click="ApplicationBarIconButton_Click" />
        <shell:ApplicationBar.MenuItems>
            <shell:ApplicationBarMenuItem Text="update" Click="ApplicationBarMenuItem_Click"/>
        </shell:ApplicationBar.MenuItems>
    </shell:ApplicationBar>
</phone:PhoneApplicationPage.ApplicationBar>

ApplicationBarэто свойство PhoneApplicationPageкласса, которое содержит реальное ApplicationBarопределение. Это не часть стандартных пространств имен XAML, но это часть следующего пространства имен, которое уже должно быть объявлено на каждой стандартной странице Windows Phone:

1
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"

Иконки кнопок объявляются прямо внутри ApplicationBarтега. Базовый класс есть ApplicationBarIconButton, и наиболее важными свойствами являются Text(описание значка) и IconUri(путь к изображению, используемому в качестве значка), в то время как Clickэто обработчик событий, который вызывается, когда пользователь нажимает кнопку.

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

Другим важным ограничением элемента ApplicationBarуправления является то, что мы не можем присвоить x:Nameсвойство элементу управления ApplicationBarIconButtonили ApplicationBarMenuItem. Это означает, что если нам нужно изменить значение свойства в коде, мы не можем просто использовать нотацию ControlName.PropertyName .

Обходной путь — использовать код для прямого доступа к коллекциям, которые содержат кнопки и пункты меню, доступные из-за ApplicationBarобъекта. Они вызываются Buttonsи MenuItems, как вы можете видеть в следующем примере кода:

1
2
3
4
ApplicationBarIconButton iconButton = this.ApplicationBar.Buttons[0] as ApplicationBarIconButton;
iconButton.Text = "New text";
ApplicationBarMenuItem menuItem = this.ApplicationBar.MenuItems[0] as ApplicationBarMenuItem;
menuItem.Text = "New text";

Цель этого примера — получить доступ к первой кнопке со значком и первому элементу меню внутри ApplicationBarи изменить значение Textсвойства.

В конце концов, есть два других способа настройки ApplicationBar. Первое — минимизировать это. Таким образом, будут отображены только три точки на правом поле; значки не будут видны Чтобы достичь этого, вы должны установить Modeсвойство Minimized.

Другой способ — изменить непрозрачность. Вы можете установить Opacityсвойство со значением от 0 (прозрачный) до 1 (непрозрачный). Самым большим отличием является то, что при ApplicationBarпрозрачности содержимое страницы будет идти ниже полосы и умещаться на весь размер экрана; когда панель непрозрачна, содержимое не будет занимать все доступное пространство экрана, так как нижняя часть страницы будет зарезервирована для ApplicationBar.

Одним из наиболее распространенных требований в приложении является отображение набора элементов, которые можно извлечь из удаленной службы или локальной базы данных. Windows Phone SDK включает с самого начала некоторые элементы управления для этой цели, такие как ItemsControlи ListBox. В Windows Phone 8 Microsoft представила новый и более мощный элемент управления, который ранее был доступен как часть Windows Phone Toolkit (более подробно об этом наборе вы узнаете позже в этой статье). Этот элемент управления называется LongListSelectorи имеет много преимуществ по сравнению с другими аналогичными элементами управления:

  • лучшая производительность
  • поддержка виртуализации, чтобы избежать загрузки всех данных одновременно, вместо этого загружая данные только тогда, когда это необходимо
  • поддержка группы, чтобы превратить список в a jump list, чтобы данные группировались по категориям и пользователи могли легко переходить от одного к другому (например, в People Hub контакты сгруппированы по первой букве)

Элемент LongListSelectorуправления можно использовать как обычный ListBoxдля отображения плоского списка элементов без группировки. В этом случае вам просто нужно установить IsGroupingEnabledсвойство в false. За исключением этой модификации, вы сможете использовать LongListSelectorкак стандарт ItemsControl. Вы определите ItemTemplateсвойство с помощью, DataTemplateчтобы определить макет элемента, и назначите коллекцию, которую вы хотите отобразить, ItemsSourceсвойству.

1
2
3
<phone:LongListSelector x:Name="List"
                       IsGroupingEnabled="False"
                       ItemTemplate="{StaticResource PeopleItemTemplate}" />

Создание списка, сгруппированного по первой букве элементов, немного сложнее, так как мы должны изменить наш источник данных. Это больше не будет простой набор данных. Кроме того, если мы хотим, чтобы взаимодействие с пользователем было совместимо с другими приложениями, нам необходимо создать список переходов со всеми буквами алфавита. Группы, в которых нет участников, будут отключены, чтобы пользователи не могли их коснуться.

Чтобы достичь этого результата, Microsoft предлагает класс под названием AlphaKeyGroup<T>, который представляет букву алфавита и все элементы, которые начинаются с него. Однако этот класс не является частью Windows Phone SDK и должен быть добавлен в проект вручную, щелкнув правой кнопкой мыши проект в обозревателе решений в Visual Studio и выбрав Добавить новый класс . В следующем примере кода приведена полная реализация.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
public class AlphaKeyGroup<T> : List<T>
{
    /// <summary>
    /// The delegate that is used to get the key information.
    /// </summary>
    /// <param name="item">An object of type T.</param>
    /// <returns>The key value to use for this object.</returns>
    public delegate string GetKeyDelegate(T item);
 
    /// <summary>
    /// The key of this group.
    /// </summary>
    private set;
 
    /// <summary>
    /// Public constructor.
    /// </summary>
    /// <param name="key">The key for this group.</param>
    public AlphaKeyGroup(string key)
    {
        Key = key;
    }
 
    /// <summary>
    /// Create a list of AlphaGroup<T> with keys set by a SortedLocaleGrouping.
    /// </summary>
    /// <param name="slg">The </param>
    /// <returns>The items source for a LongListSelector.</returns>
    private static List<AlphaKeyGroup<T>> CreateGroups(SortedLocaleGrouping slg)
    {
        List<AlphaKeyGroup<T>> list = new List<AlphaKeyGroup<T>>();
 
        foreach (string key in slg.GroupDisplayNames)
        {
            list.Add(new AlphaKeyGroup<T>(key));
        }
 
        return list;
    }
 
    /// <summary>
    /// Create a list of AlphaGroup<T> with keys set by a SortedLocaleGrouping.
    /// </summary>
    /// <param name="items">The items to place in the groups.</param>
    /// <param name="ci">The CultureInfo to group and sort by.</param>
    /// <param name="getKey">A delegate to get the key from an item.</param>
    /// <param name="sort">Will sort the data if true.</param>
    /// <returns>An items source for a LongListSelector.</returns>
    public static List<AlphaKeyGroup<T>> CreateGroups(IEnumerable<T> items, CultureInfo ci, GetKeyDelegate getKey, bool sort)
    {
        SortedLocaleGrouping slg = new SortedLocaleGrouping(ci);
        List<AlphaKeyGroup<T>> list = CreateGroups(slg);
 
        foreach (T item in items)
        {
            int index = 0;
            if (slg.SupportsPhonetics)
            {
             //Checks whether your database has the string yomi as an item.
             //If it does not, then generate Yomi or ask users for this item.
             //index = slg.GetGroupIndex(getKey(Yomiof(item)));
            }
            else
            {
                index = slg.GetGroupIndex(getKey(item));
            }
            if (index >= 0 && index < list.Count)
            {
                list[index].Add(item);
            }
        }
 
        if (sort)
        {
            foreach (AlphaKeyGroup<T> group in list)
            {
                group.Sort((c0, c1) => { return ci.CompareInfo.Compare(getKey(c0), getKey(c1)); });
            }
        }
 
        return list;
    }
 
}

Основными особенностями этого класса являются:

  • Он наследуется от List<T>, поэтому он представляет список элементов.
  • У него есть свойство под названием Key, которое является ключом, идентифицирующим группу (буква алфавита).
  • Он использует специальный тип коллекции SortedLocaleGroup, который может управлять культурными различиями между языками.
  • Он предлагает метод под названием CreateGroups(), который мы будем использовать для группировки наших данных.

Чтобы лучше объяснить, как использовать AlphaKeyGroup<T>класс, давайте приведем реальный пример. Давайте определим группу людей, которых мы хотим сгруппировать, по первым буквам их имен, аналогично тому, как это делает People Hub. Первый шаг — создать класс, представляющий одного человека:

1
2
3
4
5
6
public class Person
{
    public string Name { get;
    public string Surname { get;
    set;
}

Затем, когда приложение запускается, мы заполняем список набором поддельных данных, как показано в следующем примере:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
void LongListSelectorAlphabetic_Loaded(object sender, RoutedEventArgs e)
{
    List<Person> people = new List<Person>
    {
        new Person
        {
            Name = "John",
            Surname = "Doe",
            City = "Como"
        },
        new Person
        {
            Name = "Mark",
            Surname = "Whales",
            City = "Milan"
        },
        new Person
        {
            Name = "Ricky",
            Surname = "Pierce",
            City = "New York"
        }
    };
}

Теперь пришло время использовать AlphaGroupKey<T>класс для преобразования этого плоского списка в сгруппированный список, вызвав CreateGroups()метод.

1
2
3
List<AlphaKeyGroup<Person>> list = AlphaKeyGroup<Person>.CreateGroups(people,
   Thread.CurrentThread.CurrentUICulture,
   p => p.Name, true);

Метод требует четырех параметров:

  • Коллекция, которую мы хотим сгруппировать: в примере это коллекция Personобъектов, которые мы создали.
  • Культура, используемая для создания букв алфавита. Стандартная практика заключается в использовании значения Thread.CurrentThread.CurrentUICultureсвойства, которое является основным языком, установленным пользователем для телефона.
  • Свойство объекта, которое будет использоваться для группировки: это указывается с помощью лямбда-выражения. В примере список будет сгруппирован по первой букве имени.
  • Последний параметр, Booleanтип, используется для определения того, применять ли упорядочение: если установлено значение true, коллекция будет упорядочена в алфавитном порядке.

В ответ мы получаем набор AlphaKeyGroup<T>объектов, по одному на каждую букву алфавита. Это коллекция, которую нам нужно присвоить ItemsSourceсвойству LongListSelectorControl.

1
2
3
4
5
List<AlphaKeyGroup<Person>> list = AlphaKeyGroup<Person>.CreateGroups(people,
Thread.CurrentThread.CurrentUICulture,
p => p.Name, true);
 
People.ItemsSource = list;

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

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

1
2
3
4
5
6
7
8
9
<DataTemplate x:Key="PeopleGroupHeaderTemplate">
    <Border Background="Transparent" Padding="5">
        <Border Background="{StaticResource PhoneAccentBrush}" BorderBrush="{StaticResource PhoneAccentBrush}" BorderThickness="2" Width="62"
    Height="62" Margin="0,0,18,0" HorizontalAlignment="Left">
            <TextBlock Text="{Binding Key}" Foreground="{StaticResource PhoneForegroundBrush}" FontSize="48" Padding="6"
    FontFamily="{StaticResource PhoneFontFamilySemiLight}" HorizontalAlignment="Left" VerticalAlignment="Center"/>
        </Border>
    </Border>
</DataTemplate>

При такой раскладке письмо помещается в квадрат с цветом фона, совпадающим с цветом акцента телефона. Обратите внимание на две важные вещи:

  • Некоторые свойства элемента Borderуправления используют PhoneAccentBrushресурс. Это один из ранее описанных ресурсов темы, который определяет цвет акцента телефона.
  • TextСвойство TextBlockуправления связан с Keyсвойством AlphaGroupKey<T>класса. Таким образом, мы можем отобразить букву группы внутри квадрата.
Типичный макет заголовка группы в элементе управления LongListSelector

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

Вот примерное определение, которое, опять же, воссоздает внешний вид нативных приложений — все буквы алфавита отображаются рядом в нескольких строках.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
<phone:JumpListItemBackgroundConverter x:Key="BackgroundConverter"/>
<phone:JumpListItemForegroundConverter x:Key="ForegroundConverter"/>
<Style x:Key="PeopleJumpListStyle" TargetType="phone:LongListSelector">
    <Setter Property="GridCellSize" Value="113,113"/>
    <Setter Property="LayoutMode" Value="Grid" />
    <Setter Property="ItemTemplate">
        <Setter.Value>
            <DataTemplate>
                <Border Background="{Binding Converter={StaticResource BackgroundConverter}}" Width="113" Height="113" Margin="6" >
                    <TextBlock Text="{Binding Key}" FontFamily="{StaticResource PhoneFontFamilySemiBold}" FontSize="48" Padding="6"
        Foreground="{Binding Converter={StaticResource ForegroundConverter}}" VerticalAlignment="Center"/>
                </Border>
            </DataTemplate>
        </Setter.Value>
    </Setter>
</Style>

Этот стиль использует два преобразователя , которые являются частью Windows Phone Toolkit называется JumpListItemBackgroundConverterи JumpListItemForegroundConverter. Как видно из того, ItemTemplateчто применяется к элементу управления, эти конвертеры используются для определения цвета текста и цвета Borderфона. Их цель — управлять пустыми группами. Если коллекция содержит один или несколько элементов, она будет отображаться белым цветом с акцентом на телефоне в качестве фона. Если вместо этого буква связана с группой без элементов, текст и фон будут серыми. Таким образом, пользователи сразу видят, что группа отключена, и нажатие на нее не даст никакого эффекта.

Типичный вид списка переходов LongListSelector

В конце не забывайте, что как и для любого другого элемента управления, основанного на ItemsControlклассе, вам нужно установить ItemTemplateсвойство с помощью a, DataTemplateчтобы определить, как будет выглядеть отдельный элемент. В следующем примере показана базовая реализация, где имя и фамилия отображаются один под другим:

1
2
3
4
5
6
<DataTemplate x:Key="PeopleItemTemplate">
    <StackPanel>
        <TextBlock Text="{Binding Name}" />
        <TextBlock Text="{Binding Surname}" />
    </StackPanel>
</DataTemplate>

Собрав все необходимые стили и шаблоны, вы можете применить их к LongListSelector управления, как показано в следующем примере:

1
2
3
4
5
6
7
<phone:LongListSelector
                   x:Name="People"
                   GroupHeaderTemplate="{StaticResource PeopleGroupHeaderTemplate}"
                   ItemTemplate="{StaticResource PeopleItemTemplate}"
                   JumpListStyle="{StaticResource PeopleJumpListStyle}"
                   IsGroupingEnabled="True"
                   HideEmptyGroups="True" />

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

В некоторых случаях нам может потребоваться сгруппировать элементы по настраиваемому полю вместо первой буквы. Давайте посмотрим на другой пример. Мы хотим сгруппировать Personобъекты по Cityполю; нам нужен класс для заменыAlphaKeyGroup<T> , так как он не подходит для нашего сценария.

Давайте представим Group<T>класс, который намного проще:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
public class Group<T> : List<T>
{
    public Group(string name, IEnumerable<T> items)
        : base(items)
    {
        this.Key = name;
    }
 
    public string Key
    {
        get;
        set;
    }
}

Под капотом этот класс ведет себя как AlphaKeyGroup<T>. Он наследуется от List<T>, поэтому представляет коллекцию элементов и определяет группу, которая идентифицируется ключом (который будет именем категории).

01
02
03
04
05
06
07
08
09
10
private List<Group<T>> GetItemGroups<T>(IEnumerable<T> itemList, Func<T, string> getKeyFunc)
{
    IEnumerable<Group<T>> groupList = from item in itemList
        group item by getKeyFunc(item)
        into g
        orderby g.Key
        select new Group<T>(g.Key, g);
 
    return groupList.ToList();
}

Предыдущий метод принимает в качестве входных параметров:

  • квартира коллекции в группу.
  • функция (выраженная лямбда-выражением) для установки свойства объекта, которое мы хотим использовать для группировки

В следующем примере показан код, который мы можем использовать для группировки коллекции Personобъектов по Cityсвойству:

1
2
List<Group<Person>> groups = GetItemGroups(people, x => x.City);
PeopleByCity.ItemsSource = groups;

Результат, возвращаемый GetItemGroups()методом, может быть напрямую присвоен ItemsSourceсвойству элемента LongListSelectorуправления.

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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<phone:JumpListItemBackgroundConverter x:Key="BackgroundConverter"/>
<phone:JumpListItemForegroundConverter x:Key="ForegroundConverter"/>
 
<DataTemplate x:Key="PeopleCityGroupHeaderTemplate">
    <Border Background="Transparent" Padding="5">
        <Border Background="{StaticResource PhoneAccentBrush}" BorderBrush="{StaticResource PhoneAccentBrush}" BorderThickness="2"
    Height="62" Margin="0,0,18,0" HorizontalAlignment="Left">
            <TextBlock Text="{Binding Key}" Foreground="{StaticResource PhoneForegroundBrush}" FontSize="48" Padding="6"
    FontFamily="{StaticResource PhoneFontFamilySemiLight}" HorizontalAlignment="Left" VerticalAlignment="Center"/>
        </Border>
    </Border>
</DataTemplate>
 
<Style x:Key="PeopleCityJumpListStyle" TargetType="phone:LongListSelector">
    <Setter Property="GridCellSize" Value="113,113"/>
    <Setter Property="LayoutMode" Value="List" />
    <Setter Property="ItemTemplate">
        <Setter.Value>
            <DataTemplate>
                <Border Background="{Binding Converter={StaticResource BackgroundConverter}}" Height="113" Margin="6" >
                    <TextBlock Text="{Binding Key}" FontFamily="{StaticResource PhoneFontFamilySemiBold}" FontSize="48" Padding="6"
        Foreground="{Binding Converter={StaticResource ForegroundConverter}}" VerticalAlignment="Center"/>
                </Border>
            </DataTemplate>
        </Setter.Value>
    </Setter>
</Style>

На следующем рисунке показан результат примера кода.

Элемент управления LongListSelector, используемый для группировки коллекции по настраиваемому полю

Не забудьте собрать LongListSelectorэлемент управления, добавив все стили и шаблоны, которые вы только что создали, как показано в следующем примере:

1
2
3
4
5
6
<phone:LongListSelector
       x:Name="PeopleByCity"
       ItemTemplate="{StaticResource PeopleItemTemplate}"
       GroupHeaderTemplate="{StaticResource PeopleCityGroupHeaderTemplate}"
       JumpListStyle="{StaticResource PeopleCityJumpListStyle}"
       IsGroupingEnabled="True" />

При взаимодействии с элементом LongListSelectorуправления (или любым другим элементом управления, унаследованным от ItemsControlкласса) необходимо учитывать две ключевые концепции :

  • SelectionChangedсобытие, которое срабатывает каждый раз , когда пользователь нажимает один из элементов в списке
  • SelectedItemсвойство, которое хранит элементы , которые были выбраны пользователем

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

1
2
3
4
5
<phone:LongListSelector
       x:Name="People"
       GroupHeaderTemplate="{StaticResource PeopleGroupHeaderTemplate}"
       ItemTemplate="{StaticResource PeopleItemTemplate}"
       SelectionChanged="LongListSelectorAlphabetic_Loaded" />

В предыдущем примере показан элемент LongListSelectorуправления, который был подписан на SelectionChangedсобытие. В следующем примере вместо этого показан код обработчика события:

1
2
3
4
5
6
private void People_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
    Person selectedPerson = People.SelectedItem as Person;
    string uri = string.Format("/DetailPage.xaml?Id={0}", selectedPerson.Id);
    NavigationService.Navigate(new Uri(uri, UriKind.Relative));
}

В предыдущем примере показан элемент LongListSelectorуправления, который был подписан на SelectionChangedсобытие. В следующем примере вместо этого показан код обработчика события:

1
2
3
4
5
6
private void People_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
    Person selectedPerson = People.SelectedItem as Person;
    string uri = string.Format("/DetailPage.xaml?Id={0}", selectedPerson.Id);
    NavigationService.Navigate(new Uri(uri, UriKind.Relative));
}

Благодаря этому SelectedItemсвойству мы извлекаем выбранный Personобъект и перенаправляем пользователя на другую страницу с именемDetailPage.xaml для отображения сведений о выбранном человеке. Мы подробно рассмотрим навигацию в следующей статье.

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

Вот краткий список наиболее важных доступных элементов управления:

  • ToggleSwitch : Особенно полезно для страниц настроек, так как это переключатель, который можно использовать для определения логического значения (вкл / выкл).
  • ContextMenu : Меню, которое может отображаться, когда пользователи нажимают и удерживают элемент.
  • DatePickerи TimePicker: Используется для выбора даты или времени соответственно.
  • WrapPanel : Специальный контейнер, который может выровнять вложенные элементы управления рядом друг с другом и автоматически переносить на новую строку, если не осталось места.
  • AutoCompleteBox: Специальное предложение, TextBoxкоторое может подсказывать пользователю подсказки на основе текста, набираемого пользователем.
  • ListPicker: Используется для отображения списка элементов. Это особенно полезно, когда вы просите пользователей выбирать между различными значениями.
  • ExpanderView: Используется для создания элементов, которые можно развернуть, используя древовидную структуру для отображения других элементов. Хорошим примером этого элемента управления является приложение Почта; он используется для отображения разговоров.
  • MultiSelectList: Аналогично a ListBox, но автоматически ставит флажки рядом с каждым элементом, позволяя пользователям выбирать несколько элементов.
  • PhoneTextBox: Специальный TextBoxэлемент управления со множеством встроенных функций, таких как поддержка значков действий, заполнителей, счетчика символов и т. Д.
  • HubTile : Может использоваться для воссоздания начального экрана, предлагаемого Live Tiles, внутри приложения.
  • CustomMessageBox: Специальное MessageBoxпредложение, которое предлагает гораздо больше опций, чем стандартный, например, настройка кнопок, поддержка пользовательских шаблонов и т. Д.
  • RatingПредоставляет пользователям возможность оценивать что-либо внутри приложения. Пользовательский опыт похож на тот, который предлагает Магазин, где пользователи могут голосовать за приложение.
  • SpeechTextBoxЕще одна особенность, TextBoxкоторая поддерживает распознавание голоса, так что пользователи могут диктовать текст вместо его ввода.

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

В этой статье мы узнали, как анимировать объекты, размещенные на странице. Зачастую одним из самых простых способов улучшить внешний вид нашего приложения является добавление анимации при переходе с одной страницы на другую. Набор инструментов для Windows Phone играет важную роль в достижении этого результата, поскольку стандартный фрейм приложения, предоставляемый SDK, который управляет всеми страницами нашего приложения, не поддерживает переходы. Вместо этого инструментарий предлагает определенный класс кадров, который называется TransitionFrame, который можно использовать для замены исходного класса кадров, который вызывается PhoneApplicationFrame.

Первым шагом является замена оригинальной рамы. Вы можете сделать это в App.xaml.csфайле, который содержит скрытую область под названием « Инициализация приложения телефона» . Если вы развернете его, вы найдете метод, InitializePhoneApplication()который, помимо прочего, инициализирует фрейм приложения следующим кодом:

1
RootFrame = new PhoneApplicationFrame();

Замена оригинальной рамы очень проста. После установки Windows Phone Toolkit вы можете изменить инициализацию RootFrameобъекта с помощью TransitionFrameкласса, который является частью Microsoft.Phone.Controlsпространства имен, как показано в следующем примере:

1
RootFrame = new TransitionFrame();

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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
<toolkit:TransitionService.NavigationInTransition>
    <toolkit:NavigationInTransition>
        <toolkit:NavigationInTransition.Backward>
            <toolkit:TurnstileTransition Mode="BackwardIn"/>
        </toolkit:NavigationInTransition.Backward>
        <toolkit:NavigationInTransition.Forward>
            <toolkit:TurnstileTransition Mode="ForwardIn"/>
        </toolkit:NavigationInTransition.Forward>
    </toolkit:NavigationInTransition>
</toolkit:TransitionService.NavigationInTransition>
 
<toolkit:TransitionService.NavigationOutTransition>
    <toolkit:NavigationOutTransition>
        <toolkit:NavigationOutTransition.Backward>
            <toolkit:TurnstileTransition Mode="BackwardOut"/>
        </toolkit:NavigationOutTransition.Backward>
        <toolkit:NavigationOutTransition.Forward>
            <toolkit:TurnstileTransition Mode="ForwardOut"/>
        </toolkit:NavigationOutTransition.Forward>
    </toolkit:NavigationOutTransition>
</toolkit:TransitionService.NavigationOutTransition>

Переходы добавляются с помощью TransitionService, который является частью Windows Phone Toolkit (убедитесь, что xmlns:toolkit="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit"пространство имен добавлено на вашу страницу).

Поддерживаются два типа анимации, указанные с помощью NavigationInTransitionсвойства:

  • In анимации, которые применяются, когда пользователи переходят на текущую страницу
  • Out анимации, которые применяются, когда пользователи уходят с текущей страницы

Для каждого типа перехода у вас также есть возможность указать два дополнительных условия:

  • BackwardСвойство используется для указания перехода к использованию , когда пользователи достигают страницы после нажатия кнопки Назад.
  • ForwardСвойство используется для указания перехода использовать , когда пользователи достигают страницы с помощью обычной навигации потока.

Наконец, вы можете указать, какой переход вы хотите использовать для каждого сценария. Инструментарий предлагает список предопределенных анимаций, таких как RotateTransitionприменение эффекта вращения, TurnstileTransitionимитация просмотра книги или SlideTransitionприменение эффекта слайда. Каждый переход предлагает Modeсвойство, которое можно использовать для настройки применяемого эффекта. В предыдущем примере показан TurnstileTransitionэффект, применяемый во время каждой навигации, с различным эффектом в зависимости от типа навигации (назад или вперед).

Каркас анимации можно использовать не только для применения перехода ко всей странице, но и для каждого элемента управления на странице. Этот сценарий поддерживается TurnstileFeatherTransitionэлементом управления, который применяет эффект турникета к элементам управления на странице. Вы можете решить, какой порядок будет использоваться для анимации, и ввести элементы управления на странице со FeatheringIndexсвойством.

Первым шагом является добавление TransitionServiceна свою страницу и определение набора TurnstileFeatherTransitionанимаций, как в следующем примере:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
<toolkit:TransitionService.NavigationInTransition>
    <toolkit:NavigationInTransition>
        <toolkit:NavigationInTransition.Backward>
            <toolkit:TurnstileFeatherTransition Mode="BackwardIn"/>
        </toolkit:NavigationInTransition.Backward>
        <toolkit:NavigationInTransition.Forward>
            <toolkit:TurnstileFeatherTransition Mode="ForwardIn"/>
        </toolkit:NavigationInTransition.Forward>
    </toolkit:NavigationInTransition>
</toolkit:TransitionService.NavigationInTransition>
<toolkit:TransitionService.NavigationOutTransition>
    <toolkit:NavigationOutTransition>
        <toolkit:NavigationOutTransition.Backward>
            <toolkit:TurnstileFeatherTransition Mode="BackwardOut"/>
        </toolkit:NavigationOutTransition.Backward>
        <toolkit:NavigationOutTransition.Forward>
            <toolkit:TurnstileFeatherTransition Mode="ForwardOut"/>
        </toolkit:NavigationOutTransition.Forward>
    </toolkit:NavigationOutTransition>
</toolkit:TransitionService.NavigationOutTransition>

Затем вы можете применить TurnstileFeatherTransition.FeatheringIndexсвойство к любому элементу управления на странице и указать порядок, в котором они будут отображаться, начиная с 0, чтобы задать первый элемент управления, который будет вводиться на странице.

1
2
3
4
5
6
7
8
<StackPanel>
    <TextBlock Text="First Element"                       
                toolkit:TurnstileFeatherEffect.FeatheringIndex="0"/>
    <TextBlock Text="Second Element"
                toolkit:TurnstileFeatherEffect.FeatheringIndex="1"/>
    <TextBlock Text="Third Element"
                toolkit:TurnstileFeatherEffect.FeatheringIndex="2"/>
</StackPanel>

В предыдущем примере TextBlockна странице появятся три элемента управления, начиная с первого (значение которого FeatheringIndexравно 0) и заканчивая последним (значение которого FeatheringIndexравно 2).

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

  • Мы ввели основные концепции XAML, такие как свойства, события, пространства имен и ресурсы.
  • Мы узнали, как работает привязка данных. Это одна из самых мощных функций XAML, и очень важно понимать ее как продуктивную.
  • Мы видели некоторые из основных элементов управления, которые включены в SDK, и как мы можем использовать их для определения пользовательского интерфейса нашего приложения.
  • Мы обсудили некоторые элементы управления , которые являются специфическими для опыта Windows Phone, как Panorama, Pivotи ApplicationBarуправление.

Это руководство представляет собой главу из Windows Phone 8 Succinctly , бесплатной электронной книги от команды Syncfusion.