Главная » Разработка для Windows Phone 7 » Наследование от UserControl

0

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

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

Если вы занимаетесь созданием элементов управления на коммерческой основе, создаваемые и продаваемые вами пользовательские элементы управления должны наследоваться от Control или ContentControl, или ItemsControl (Элемент управления списками) (глава 17). Сменный шаблон является важнейшей составляющей коммерческих элементов управления.

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

Для таких элементов управления идеальным решением часто является наследование от UserControl. (User (Пользователь) в UserControl – это вы, разработчик.) Более того, у нас уже имеется опыт наследования от UserControl! Класс PhoneApplicationPage наследуется от Page, который является производным от UserControl.

UserControl имеет свойство Content типа UIElement. При наследовании от UserControl новые свойства обычно определяются в коде (и часто также методы и события), но визуальные элементы описываются в XAML через задание дерева визуальных элементов для свойства Content. Это делает невозможным использование свойства Content для каких-либо иных целей. Если производный от UserControl класс должен включать свойство Content, следует описать новое свойство Child или что-то подобное для использования в тех же целях.

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

Например, в XAML-файле приложения ColorScroll из предыдущей главы было много повторяющихся фрагментов: три строки, каждая из которых включала Slider и два элемента TextBlock. Чтобы адаптировать идею ColorScroll в пригодный для повторного использования элемент управления, возможно, следует начать с наследования класса ColorColumn (Цветовая дорожка) от UserControl и затем поместить три элемента управления ColorColumn в производный от UserControl класс RgbColorScroller (Полоса прокрутки RGB-цвета).

Оба класса, ColorColumn и RgbColorScroller, можно найти в проекте библиотеки динамической компоновки (DLL) под названием Petzold.Phone.Silverlight. Создать DLL в Visual Studio для приложений Windows Phone просто: в диалоговом окне New Project в левой панели выбираем Silverlight for Windows Phone и в средней панели – Windows Phone Class Library (Библиотека классов Windows Phone). (Для целей тестирования следует либо создать второй проект приложения в том же решении в качестве библиотеки; либо пользовательские классы можно создавать в проекте приложения и переносить их в библиотеку после тестирования.)

В проект Petzold.Phone.Silverlight (или любой другой проект библиотеки) можно добавить новый элемент. Для этого в Solution Explorer щелкните правой кнопкой мыши имя проекта и выберите в появившемся меню Add и New Item.

Чтобы создать новый UserControl в проекте приложения или библиотеки, в диалоговом окне Add New Item выберите Windows Phone User Control (Пользовательский элемент управления Windows Phone) и задайте его имя. В результате этого будет создано два файла: XAML-файл и файл выделенного кода.

XAML-файл намного проще того, который был создан для класса PhoneApplicationPage. Корневым элементом в нем является UserControl. Он включает атрибут x:Class, обозначающий, что это производный класс, и единственный вложенный элемент – Grid под именем LayoutRoot. В этом Grid нет необходимости, но с ним удобней.

Корневой элемент включает атрибуты для задания следующих свойств:

FontFamily="{StaticResource PhoneFontFamilyNormal}" FontSize="{StaticResource PhoneFontSizeNormal}" Foreground="{StaticResource PhoneForegroundBrush}"

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

Также я удалил атрибуты, связанные с дизайнером. Итак, рассмотрим файл ColorColumn.xaml полностью. Обратите внимание, что я изменил значение свойства Background для Grid. Ранее для него использовался StaticResource, ссылающийся на PhoneChromeBrush, теперь его значение Transparent:

Проект Silverlight: Petzold.Phone.Silverlight Файл: ColorColumn.xaml

<UserControl

x:Class="Petzold.Phone.Silverlight.ColorColumn"

xmlns="http://schemas.microsoft.com/winfx/2 0 0 6/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2 0 0 6/xaml">

<Grid x:Name="LayoutRoot" Background="Transparent"> <Grid.RowDefinitions>

<RowDefinition Height="Auto" /> <RowDefinition Height="*" /> <RowDefinition Height="Auto" /> </Grid.RowDefinitions>

<TextBlock Name="colorLabel" Grid.Row="0"

TextAlignment="Center" />

<Slider Name="slider" Grid.Row="1" 0rientation="Vertical" Minimum="0" Maximum="255"

ValueChanged="0nSliderValueChanged" />

<TextBlock Name="colorValue" Grid.Row="2" Text="0 0"

TextAlignment="Center" />

</Grid> </UserControl>

Grid включает три строки. В верхней строке располагается TextBlock под именем colorLabel (Цвет), затем следует Slider с диапазоном значений от 0 до 255 и еще один TextBlock, называющийся colorValue (Значение цвета). В Slider задан обработчик события OnSliderValueChanged.

В примере ColorScroll предыдущей главы элементы управления Slider и элементы TextBlock закрашивались красным, зеленым или синим посредством свойства Foreground. Поскольку свойство Foreground наследуется через дерево визуальных элементов, достаточно задать его один раз для любого экземпляра ColumnColumn и позволить ему наследоваться вниз по дереву.

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

Это означает, что класс ColorColumn описывает два свойства: свойство Label (Надпись), а также более ожидаемое свойство Value, значение которого соответствует положению Slider. Как и сам Slider, класс ColorColumn тоже определяет событие ValueChanged, сигнализирующее о моменте изменения значения Slider.

Как правило, производный от UserControl класс описывает собственные свойства и события, и очень часто эти свойства и события повторяют свойства и события элементов его визуального дерева. Типично для такого класса, как ColorColumn, иметь свойство Label, соответствующее свойству Text элемента TextBlock, и свойство Value, соответствующее свойству Value элемента Slider, а также событие ValueChanged, соответствующее событию ValueChanged элемента Slider.

Рассмотрим фрагмент файла выделенного кода ColorColumn, описывающий свойство Label, которое обеспечивает вывод надписи над Slider:

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

public partial class ColorColumn : UserControl {

public static readonly DependencyProperty LabelProperty = DependencyProperty.Register("Label", typeof(string), typeof(ColorColumn),

new PropertyMetadata(OnLabelChanged));

public string Label {

set { SetValue(LabelProperty, value); }

get { return (string)GetValue(LabelProperty); }

}

static void OnLabelChanged(DependencyObject obj,

DependencyPropertyChangedEventArgs args)

{

(obj as ColorColumn).colorLabel.Text = args.NewValue as string;

}

}

Обработчик изменения значения свойства Label просто задает значение свойства Text элемента colorLabel. Это один из способов передачи значения свойства из пользовательского элемента управления в свойство элемента дерева визуальных элементов. В следующей главе я продемонстрирую более простой подход с использованием привязки данных.

Свойство Value в ColorColumn несколько сложнее, потом что оно должно формировать событие ValueChanged. Это свойство Value в итоге используется при вычислении значения Color, поэтому я сделал его типа byte, а не double. Рассмотрим код класса, описывающий свойство Value и событие ValueChanged:

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

public partial class ColorColumn : UserControl {

public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(byte), typeof(ColorColumn),

new PropertyMetadata((byte)0, 0nValueChanged)); public event RoutedPropertyChangedEventHandler<byte> ValueChanged;

public byte Value {

set { SetValue(ValueProperty, value); }

get { return (byte)GetValue(ValueProperty); }

}

static void 0nValueChanged(Dependency0bject obj,

DependencyPropertyChangedEventArgs args)

{

(obj as ColorColumn).0nValueChanged((byte)args.0ldValue,

(byte)args.NewValue); }

protected virtual void 0nValueChanged(byte oldValue, byte newValue) {

slider.Value = newValue;

colorValue.Text = newValue.ToString("X2");

if (ValueChanged != null) ValueChanged(this,

new RoutedPropertyChangedEventArgs<byte>(oldValue, newValue));

}

}

Для описания события ValueChanged я использовал универсальный

RoutedPropertyChangedEventHandler (Обработчик маршрутизируемого события изменения значения свойства) и соответствующий RoutedPropertyChangedEventArgs (Аргументы маршрутизируемого события изменения значения свойства). Они хороши для сигнализации об изменении значения свойства-зависимости, потому что обеспечивают передачу старого и нового значения.

Статический метод OnValueChanged вызывает защищенный виртуальный метод экземпляра с таким же именем, OnValueChanged, но его аргументы указывают на старое и новое значения свойства. (На создание моей версии меня вдохновил метод OnValueChanged класса RangeBase.) Этот метод экземпляра устанавливает Slider и задает значение TextBlock соответственно текущему значению и формирует событие ValueChanged.

В коде ColorColumn нам осталось обсудить только лишь конструктор и обработчик события ValueChanged объекта Slider. Этот обработчик события просто приводит свойство Value класса Slider к типу byte и присваивает ему значение свойства Value класса ColorColumn.

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

public partial class ColorColumn : UserControl {

public ColorColumn() {

InitializeComponent();

}

void OnSliderValueChanged(object sender,

RoutedPropertyChangedEventArgs<double> args)

{

Value = (byte)args.NewValue;

}

}

И здесь можно выявить бесконечный цикл: пользователь перемещает ползунок, объект Slider формирует событие ValueChanged, метод OnSliderValueChanged задает значение свойству Value объекта ColorColumn, вызывается статический обработчик события изменения значения свойства, статический метод вызывает метод экземпляра OnValueChanged, который задает значение свойства Value объекта Slider, что приводит к формированию следующего события ValueChanged, и т.д.

В реальности этого не происходит, потому что в некоторый момент одному из этих свойств Value – либо Value объекта Slider, либо Value объекта ColorColumn – будет присвоено его текущее значение, т.е. событие изменения свойства сформировано не будет. Цикл прервется.

Класс RgbColorScroller также наследуется от UserControl и включает три элемента управления ColorColumn. Привожу XAML-файл полностью:

Проект Silverlight: Petzold.Phone.Silverlight Файл: RgbColorScroller.xaml

<UserControl

x:Class="Petzold.Phone.Silverlight.RgbColorScroller" 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:petzold="clr-namespace:Petzold.Phone.Silverlight">

<Grid x:Name="LayoutRoot" Background="Transparent"> <Grid.ColumnDefinitions>

<ColumnDefinition Width="*" /> <ColumnDefinition Width="*" /> <ColumnDefinition Width="*" /> </Grid.ColumnDefinitions>

<petzold:ColorColumn x:Name="redColumn" Grid.Column="0" Foreground="Red" Label="Red"

ValueChanged="OnColorColumnValueChanged" />

<petzold:ColorColumn x:Name="greenColumn" Grid.Column="1" Foreground="Green" Label="Green"

ValueChanged="OnColorColumnValueChanged" />

<petzold:ColorColumn x:Name="blueColumn" Grid.Column="2" Foreground="Blue" Label="Blue"

ValueChanged="OnColorColumnValueChanged" />

</Grid> </UserControl>

Свойству Foreground каждого из трех элементов управления ColorColumn задан один из трех цветов. Свойствам Label заданы аналогичные значения, но типа string, а не Color.

Обратите внимание, каждый ColorColumn идентифицирован с помощью атрибута x:Name, а не Name. Обычно я использую Name, но для ссылки на класс из той же сборки Name использоваться не может, а у нас оба класса, ColorColumn и RgbColorScroller, располагаются в сборке Petzold.Phone.Silverlight.

Класс RgbColorScroller определяет одно свойство с именем Color (типа Color, конечно) и событие ColorChanged. Рассмотрим класс полностью:

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

public partial class RgbColorScroller : UserControl {

public static readonly DependencyProperty ColorProperty = DependencyProperty.Register("Color", typeof(Color), typeof(RgbColorScroller),

new PropertyMetadata(Colors.Gray, 0nColorChanged)); public event RoutedPropertyChangedEventHandler<Color> ColorChanged;

public RgbColorScroller() {

InitializeComponent();

}

public Color Color {

set { SetValue(ColorProperty, value); }

get { return (Color)GetValue(ColorProperty); }

}

void 0nColorColumnValueChanged(object sender,

RoutedPropertyChangedEventArgs<byte> args)

{

Color = Color.FromArgb(255, redColumn.Value,

greenColumn.Value, blueColumn.Value);

}

static void 0nColorChanged(Dependency0bject obj,

DependencyPropertyChangedEventArgs args)

{

(obj as RgbColorScroller).0nColorChanged((Color)args.0ldValue,

(Color)args.NewValue);

}

protected virtual void 0nColorChanged(Color oldValue, Color newValue) {

redColumn.Value = newValue.R; greenColumn.Value = newValue.G; blueColumn.Value = newValue.B;

if (ColorChanged != null) ColorChanged(this,

new RoutedPropertyChangedEventArgs<Color>(oldValue, newValue));

При изменении значения свойства Color вызывается два метода OnColorChanged. Они приводят значения свойства Color к типу byte, задают значения свойствам Value каждого из объектов ColorColumn и формируют событие ColorChanged.

Обработчик OnColorColumnValueChanged (При изменении значения цвета столбца) вызывается при формировании события ValueChanged одним из трех элементов управления ColorColumn. Этот обработчик выполняет агрегацию трех значений цвета типа byte, полученных от трех элементов управления ColorColumn, в одно значение Color.

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

Чтобы использовать класс RgbColorScroller из библиотеки Petzold.Phone.Silverlight, создаем новый проект приложения. Назовем его SelectTwoColors (Выбор двух цветов). В Solution Explorer щелкнем правой кнопкой мыши заголовок References под именем проекта и выберем Add Reference. В открывшемся диалоговом окне Add Reference выбираем вкладку Browse (Обзор). Переходим к файлу DLL (в данном случае к Petzold.Phone.Silverlight.dll) и выбираем его.

В файл MainPage.xaml понадобится включить объявление пространства имен XML для этой библиотеки. Поскольку библиотека является отдельной сборкой, в этом объявлении должен быть раздел assembly (сборка) для ссылки на файл DLL:

xmlns:petzold="clr-

namespace:Petzold.Phone.Silverlight;assembly=Petzold.Phone.Silverlight"

В XAML-файле SelectTwoColors имеется два элемента управления, каждый из которых располагается в Border, и между ними элемент Rectangle. События ColorChanged обоих RgbColorScroll ассоциированы с одним обработчиком:

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

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

<ColumnDefinition Width="*" /> <ColumnDefinition Width="*" /> <ColumnDefinition Width="*" /> </Grid.ColumnDefinitions>

<Border Grid.Column="0"

BorderBrush="{StaticResource PhoneForegroundBrush}"

BorderThickness="2"

Margin="12"

Padding="12">

<petzold:RgbColorScroller

Name="colorScroller1"

ColorChanged="OnColorScrollerColorChanged" />

</Border>

<Rectangle Name="rectangle" Grid.Column="1" StrokeThickness="2 4" Margin="12" />

<Border Grid.Column="2"

BorderBrush="{StaticResource PhoneForegroundBrush}"

BorderThickness="2"

Margin="12"

Padding="12">

<petzold:RgbColorScroller

Name="colorScroller2"

ColorChanged="0nColorScrollerColorChanged" />

</Border> </Grid>

Конструктор файла выделенного кода инициализирует эти два элемента управления RgbColorScroller, задавая каждому значение цвета. Это приводит к формированию первых событий ColorChanged. Обработчик событий обрабатывает их и задает цвета Rectangle:

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

public partial class MainPage : PhoneApplicationPage {

public MainPage() {

InitializeComponent();

colorScroller1.Color = Color.FromArgb(0xFF, 0xC0, 0x80, 0x40); colorScroller2.Color = Color.FromArgb(0xFF, 0x40, 0x80, 0xC0);

}

void 0nColorScrollerColorChanged(object sender,

RoutedPropertyChangedEventArgs<Color> args)

{

Brush brush = new SolidColorBrush(args.NewValue);

if (sender == colorScroller1) rectangle.Stroke = brush;

else if (sender == colorScroller2) rectangle.Fill = brush;

}

}

Посмотрим, что мы получаем в альбомном режиме отображения:

Обратите внимание, подписи в каждом элементе управления ColorColumn подхватили значение свойства Foreground через наследование свойств. Со Slider этого не произошло. Я подозреваю, что свойство Foreground задано в стиле темы Slider и это блокирует наследование свойств. Если бы наследование этого свойства было действительно важным, возможно, я бы описал новое свойство Color для ColorColumn и использовал его для программного задания свойства Foreground объекта Slider.

Я намеренно спроектировал компоновку SelectTwoColors так, чтобы она плохо смотрелась в портретном режиме:

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

В своем примере я не собираюсь дублировать более сложное движение. Моя версия переключателя будет отвечать только на касания. Поэтому я назвал его TapSlideToggle (Переключатель, переключающийся по касанию). Кнопка – это производный от UserControl класс, размещающийся в библиотеке Petzold.Phone.Silverlight. (Должен заметить, что-то подобное можно реализовать полностью в шаблоне, применяемом к существующему ToggleButton, и набор инструментов Silverlight for Windows Phone Toolkit реализовывает этот элемент управления под именем ToggleSwitchButton.) Рассмотрим полный XAML-файл моей версии реализации:

Проект Silverlight: Petzold.Phone.Silverlight Файл: TapSlideToggle.xaml

<UserControl x:Class="Petzold.Phone.Silverlight.TapSlideToggle"

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:d="http://schemas.microsoft.com/expression/blend/2 0 0 8"

xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2 0 0 6"

mc:Ignorable="d"

d:DesignHeight="3 6" d:DesignWidth="9 6">

<Grid x:Name="LayoutRoot"

Background="Transparent" Width="96" Height="3 6">

<Border BorderBrush="{StaticResource PhoneForegroundBrush}" BorderThickness="2" Margin="4 2" Padding="4"> <Rectangle Name="fillRectangle"

Fill="{StaticResource PhoneAccentBrush}" Visibility="Collapsed" />

</Border>

<Border Name="slideBorder"

BorderBrush="{StaticResource PhoneBackgroundBrush}" BorderThickness="4 0" HorizontalAlignment="Left"> <Rectangle Stroke="{StaticResource PhoneForegroundBrush}" Fill="White" StrokeThickness="2"

Width="2 0" />

</Border> </Grid> </UserControl>

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

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

Чтобы сделать наш переключатель хоть немного похожим на обычный ToggleButton (но без опции трех состояний), в файле выделенного кода определяем свойство-зависимость IsChecked типа bool и два события: Checked и Unchecked. При изменении значения свойства IsChecked формируется одно из этих событий:

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

public partial class TapSlideToggle : UserControl {

public static readonly DependencyProperty IsCheckedProperty = DependencyProperty.Register("IsChecked", typeof(bool), typeof(TapSlideToggle),

new PropertyMetadata(false, OnlsCheckedChanged));

public event RoutedEventHandler Checked; public event RoutedEventHandler Unchecked;

public TapSlideToggle() {

InitializeComponent();

}

public bool IsChecked {

set { SetValue(IsCheckedProperty, value); }

get { return (bool)GetValue(IsCheckedProperty); }

}

static void OnIsCheckedChanged(DependencyObject obj,

DependencyPropertyChangedEventArgs args)

{

(obj as TapSlideToggle).OnIsCheckedChanged(args);

}

void OnIsCheckedChanged(DependencyPropertyChangedEventArgs args) {

fillRectangle.Visibility = IsChecked ? Visibility.Visible :

Visibility.Collapsed;

slideBorder.HorizontalAlignment = IsChecked ? HorizontalAlignment.Right :

HorizontalAlignment.Left;

if (IsChecked && Checked != null)

Checked(this, new RoutedEventArgs());

if (!IsChecked && Unchecked != null)

Unchecked(this, new RoutedEventArgs());

}

}

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

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

protected override void 0nManipulationStarted(ManipulationStartedEventArgs args) {

args.Handled = true; base.0nManipulationStarted(args);

}

protected override void 0nManipulationCompleted(ManipulationCompletedEventArgs args) {

Point pt = args.Manipulation0rigin;

if (pt.X > 0 && pt.X < this.ActualWidth && pt.Y > 0 && pt.Y < this.ActualHeight) IsChecked Л= true;

args.Handled = true;

base.0nManipulationCompleted(args);

}

Я решил переключать кнопку, только если пользователь нажимает и затем отпускает ее, оставляя при этом палец на кнопке. Это обычный подход. Перегруженное событие OnManipulationStarted задает свойству Handled (Обработано) значение true, чтобы не допустить распространение события вверх по дереву визуальных элементов, и как результат просигнализировать, что кнопка производит данную манипуляцию. После этого перегруженное событие OnManipulationCompleted проверяет, попадает ли значение свойства ManipulationOrigin (Центр манипуляции) в границы элемента управления. Если да, свойство IsChecked меняет значение на противоположное:

IsChecked Л= true;

Протестируем функциональность с помощью приложения TapSlideToggleDemo. Область содержимого определяет два экземпляра TapSlideToggle и два элемента TextBlock для отображения их текущего состояния:

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

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

<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" /> </Grid.RowDefinitions>

<Grid.ColumnDefinitions>

<ColumnDefinition Width="*" /> <ColumnDefinition Width="*" /> </Grid.ColumnDefinitions>

<TextBlock Name="option1TextBlock"

Grid.Row="0" Grid.Column="0"

Text="off"

Margin="4 8"

VerticalAlignment="Center" />

<petzold:TapSlideToggle Name="slideToggle1"

Grid.Row="0" Grid.Column="1" Margin="4 8"

HorizontalAlignment="Right" Checked="OnSlideToggle1Checked" Unchecked="OnSlideToggle1Checked" />

<TextBlock Name="option2TextBlock"

Grid.Row="1" Grid.Column="0"

Text="off"

Margin="4 8"

VerticalAlignment="Center" />

<petzold:TapSlideToggle Name="slideToggle2"

Grid.Row="1" Grid.Column="1" Margin="4 8"

HorizontalAlignment="Right" Checked="OnSlideToggle2Checked" Unchecked="OnSlideToggle2Checked" />

</Grid>

События Checked и Unchecked экземпляра TapSlideToggle обрабатываются одним обработчиком, но для каждого экземпляра TapSlideToggle существует свой обработчик этих событий. Благодаря этому каждый обработчик может определять состояние кнопки, получая значение свойства IsChecked и задавая соответствующее значение TextBlock:

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

public partial class MainPage : PhoneApplicationPage {

public MainPage() {

InitializeComponent(); slideToggle2.IsChecked = true;

}

void OnSlideToggle1Checked(object sender, RoutedEventArgs args) {

TapSlideToggle toggle = sender as TapSlideToggle; option1TextBlock.Text = toggle.IsChecked ? "on" : "off";

}

void OnSlideToggle2Checked(object sender, RoutedEventArgs args) {

TapSlideToggle toggle = sender as TapSlideToggle; option2TextBlock.Text = toggle.IsChecked ? "on" : "off";

}

}

И вот результат:

Для этой кнопки не предусмотрено визуальное представление неактивного состояния. Когда свойству IsEnabled задано значение false, элемент управления автоматически перестает получать пользовательский ввод, но визуальная передача этого состояния должна быть реализована самим элементом управления. Обычно для этого используют полупрозрачный черный Rectangle, который перекрывает весь элемент управления. Когда кнопка активна, свойство Visibility этого прямоугольника имеет значение Collapsed. Когда свойство IsEnabled принимает значение true, свойству Visibility этого Rectangle задается значение Visible, что приводит к эффекту «затенения» визуальных элементов элемента управления.

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

По теме:

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