Главная » Разработка для Windows Phone 7 » Библиотека пользовательских элементов управления Windows Phone 7

0

Как правило, при создании пользовательского элемента управления для него описываются некоторые новые свойства, а также Style и ControlTemplate по умолчанию, и этот новый элемент управления помещается в DLL для совместного использования множеством приложений. Можно объединять код элемента управления и Style, как было показано в примере FlipToggleButton, но более стандартным подходом для библиотек Silverlight является описание Style в специальном файле generic.xaml, который располагается в папке Themes. Корневым элементом этого файла generic.xaml является ResourceDictionary.

Рассмотрим пример.

Предположим, мы хотим создать шаблон ToggleButton, подобный реализованному в проекте CustomButtonTemplate, но сделать его более обобщенным. Вместо того чтобы переключаться между двумя текстовыми строками, заданными в коде, мы хотим переключаться между двумя объектами любого типа. И не просто переключаться, мы хотим, чтобы объект, ассоциированный с состоянием Checked, и объект, ассоциированный с состоянием Unchecked, плавно перетекали друг в друга. Назовем эту новую кнопку FadableToggleButton (Переключатель с плавным переходом).

Проанализировав все это, мы понимаем, что элементу управления необходимо новое свойство CheckedContent (Содержимое в состоянии Checked), подобное обычному свойству Content. Свойство Content – это объект, отображаемый, когда кнопка находится в состоянии Unchecked, а CheckedContent – объект, отображаемый для состояния Checked.

Я описал этот класс в библиотеке Petzold.Phone.Silverlight. Привожу здесь код FadableToggleButton полностью:

Проект Silverlight: Petzold.Phone.Silverlight Файл: FadableToggleButton.cs

using System.Windows;

using System.Windows.Controls.Primitives;

namespace Petzold.Phone.Silverlight {

public class FadableToggleButton : ToggleButton {

public static readonly DependencyProperty CheckedContentProperty = DependencyProperty.Register("CheckedContent", typeof(object), typeof(FadableToggleButton), new PropertyMetadata(null));

public FadableToggleButton() {

this.DefaultStyleKey = typeof(FadableToggleButton);

}

public object CheckedContent {

set { SetValue(CheckedContentProperty, value); }

get { return (object)GetValue(CheckedContentProperty); }

}

}

}

И это весь код на C#, необходимый для реализации данного элемента управления! В нем даже нет обработчика события изменения значения для нового свойства CheckedContent. Только определение DependencyProperty и свойства CLR. Все остальное – это XAML.

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

this.DefaultStyleKey = typeof(FadableToggleButton);

Данное выражение указывает на то, что этот класс имеет определение Style по умолчанию, и значением TargetType в этом Style является FadableToggleButton. Чтобы применить Style по умолчанию к экземплярам класса, Silverlight должен найти описание этого Style. Где его искать?

Silverlight ведет поиск в особом XAML-файле библиотеки. Этот XAML-файл всегда называется generic.xaml и всегда располагается в папке Themes проекта DLL. Так элемент управления получает стиль темы и шаблон по умолчанию.

Корневым элементом файла generic.xaml file является ResourceDictionary. Но этот файл является особым по другой причине: его содержимое рассматривается как ресурсы, но элементы Style не требуют атрибутов x:Key или x:Name, потому что ссылка на них осуществляется через TargetType.

Рассмотрим часть файла generic.xaml из папки Themes библиотеки Petzold.Phone.Silverlight, которая включает описание Style по умолчанию класса FadableToggleButton:

Проект Silverlight: Petzold.Phone.Silverlight Файл: Themes/generic.xaml (фрагмент)

<ResourceDictionary

xmlns="http://schemas.microsoft.com/winfx/2 0 0 6/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2 0 0 6/xaml" xmlns:local="clr-namespace:Petzold.Phone.Silverlight">

<Style TargetType="local:FadableToggleButton"> <Setter Property="Template"> <Setter.Value>

<ControlTemplate TargetType="local:FadableToggleButton"> <Grid>

<VisualStateManager.VisualStateGroups> <VisualStateGroup x:Name="CommonStates"> <VisualState x:Name="Normal" /> <VisualState x:Name="MouseOver" /> <VisualState x:Name="Pressed" />

<VisualState x:Name="Disabled"> <Storyboard>

<DoubleAnimation Storyboard.TargetName="disableRect" Storyboard.TargetProperty="Opacity" To="0.6" Duration="0:0:0" />

</Storyboard> </VisualState> </VisualStateGroup>

<VisualStateGroup x:Name="CheckStates"> <VisualState x:Name="Checked"> <Storyboard>

<DoubleAnimation Storyboard.TargetName="uncheckedContent" Storyboard.TargetProperty="Opacity" To="0" Duration="0:0:0.5" /> <DoubleAnimation Storyboard.TargetName="checkedContent" Storyboard.TargetProperty="Opacity" To="1" Duration="0:0:0.5" />

</Storyboard> </VisualState>

<VisualState x:Name="Unchecked"> <Storyboard>

<DoubleAnimation Storyboard.TargetName="uncheckedContent" Storyboard.TargetProperty="Opacity" Duration="0:0:0.5" /> <DoubleAnimation Storyboard.TargetName="checkedContent" Storyboard.TargetProperty="Opacity" Duration="0:0:0.5" />

</Storyboard> </VisualState> </VisualStateGroup> </VisualStateManager.VisualStateGroups>

<Border BorderBrush="{StaticResource PhoneForegroundBrush}"

BorderThickness="{StaticResource PhoneBorderThickness}" Background="{TemplateBinding Background}">

<Grid Margin="{TemplateBinding Padding}"> <ContentPresenter

Name="uncheckedContent" Content="{TemplateBinding Content}"

ContentTemplate="{TemplateBinding ContentTemplate}" HorizontalAlignment="{TemplateBinding

HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding

VerticalContentAlignment}" />

<ContentPresenter

Name="checkedContent" 0pacity="0"

Content="{TemplateBinding CheckedContent}" ContentTemplate="{TemplateBinding ContentTemplate}" HorizontalAlignment="{TemplateBinding

HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding

VerticalContentAlignment}" />

</Grid> </Border>

<Rectangle Name="disableRect"

Fill="{StaticResource PhoneBackgroundBrush}" 0pacity="0" />

</Grid> </ControlTemplate> </Setter.Value> </Setter> </Style>

</ResourceDictionary>

Значением TargetType для Style является FadableToggleButton, и этого достаточно, чтобы Silverlight мог найти определение Style, который становится темой по умолчанию для FadableToggleButton. В Border располагается Grid с одной ячейкой. Grid включает два элемента ContentPresenter: свойство TemplateBinding одного из них ссылается на обычное свойство Content, и другого – на свойство CheckedContent. Свойству Opacity объекта ContentPresenter, ссылающего на свойство CheckedContent, задано начальное значение нуль. Целью анимаций для состояний Checked и Unchecked является свойство Opacity объекта ContentPresenter, что обеспечивает постепенное появление одного объекта и исчезновение другого.

Несмотря на то что свойства Content этих двух элементов ContentPresenter связаны с двумя разными свойствами FadableToggleButton, свойства ContentTemplate обоих связаны с тем же свойством ContentTemplate, которое изначально определено ContentControl. Если значением DataTemplate свойства ContentTemplate задать FadableToggleButton, тот же DataTemplate должен применяться к обоим свойствам Content и свойству CheckedContent. Иначе говоря, этот шаблон неявно предполагает, что свойства Content и CheckedContent одного типа.

Чтобы протестировать этот новый элемент управления, я создал приложение FadableToggleDemo (Демонстрация переключателя с плавным переходом). Этот проект включает ссылку на библиотеку Petzold.Phone.Silverlight и объявление пространства имен XML для библиотеки в MainPage.xaml. В папку Images этого проекта я добавил два растровых изображения одного размера. Эти изображения используются элементами Image, заданными как значения свойств Content и CheckedContent кнопки:

Проект Silverlight: FadableToggleDemo Файл: MainPage.xaml (фрагмент)

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">

<petzold:FadableToggleButton HorizontalAlignment="Center"

VerticalAlignment="Center">

<petzold:FadableToggleButton.Content>

<Image Source="Images/MunchScream.jpg"

Stretch="None" /> </petzold:FadableToggleButton.Content>

<petzold:FadableToggleButton.CheckedContent> <Image Source="Images/BotticelliVenus.jpg" Stretch="None" /> </petzold:FadableToggleButton.CheckedContent>

</petzold:FadableToggleButton>

</Grid>

Для свойства CheckedContent используется фрагмент картины Боттичелли Рождение Венеры:

Для свойства Content property используется картинаЭдварда Мунка Крик:

 

Источник: Чарльз Петзольд, Программируем Windows Phone 7, Microsoft Press, © 2011.

По теме:

  • Комментарии