WPF: пользовательские элементы

Автор работы: Пользователь скрыл имя, 19 Октября 2012 в 19:18, реферат

Описание

Что собой представляют пользовательские элементы в WPF
Хотя пользовательский элемент можно построить в любом проекте WPF, обычно такие элементы размещаются в специально выделенной сборке — библиотеке классов (DLL). Это позволяет разделять работу с множеством приложений WPF.

Работа состоит из  1 файл

Реферат WPF.docx

— 194.52 Кб (Скачать документ)

Что собой представляют пользовательские элементы в WPF

Хотя пользовательский элемент  можно построить в любом проекте WPF, обычно такие элементы размещаются  в специально выделенной сборке —  библиотеке классов (DLL). Это позволяет  разделять работу с множеством приложений WPF.

Чтобы гарантировать наличие  всех необходимых ссылок на сборки и импорт всенужных пространств  имен, при создании приложения в Visual Studio в качестве типа проекта следует  выбрать Custom Control Library (WPF) (Библиотека пользовательских элементов управления (WPF)). Внутри библиотеки классов можно создавать сколько  угодно элементов управления.

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

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

Таблица 1. Базовые  классы для создания пользовательских элементов 

Имя

Описание

FrameworkElement

Это — самый низкий уровень, с которым обычно приходится иметь  дело

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

выбирается только тогда, когда нужно нарисовать его содержимое "с нуля"

посредством переопределения OnRenderO и использования System.

Windows.Media.DrawingContext.

Класс FrameworkElement

предоставляет лишь самый  базовый набор свойств и событий  для 

элементов, которые не предназначены  для взаимодействия с пользователем 

Control

Этот класс чаще всего  служит начальной точкой при построении элемента

управления "с нуля". Это — базовый класс для  всех взаимодействующих 

с пользователем графических  элементов управления. Класс Control

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

шрифта и выравнивания содержимого. Кроме того, этот класс 

помещает себя в последовательность обхода по клавише <ТаЬ> (свойством 

isTabStop) и получает уведомления  о двойном щелчке (через события 

MouseDoubleClick и PreviewMouseDoubleClick). Но что более

важно, так это то, что  класс Control определяет свойство Template,

позволяющее заменять его  внешний вид с неограниченной гибкостью 

ContentControl

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

отображаться как единое целое с произвольным содержимым. Содержимое

может быть элементом пользовательского  объекта, применяемого

в сочетании с шаблоном. (Содержимое устанавливается свойством

Content, а необязательный  шаблон может быть представлен  в 

свойстве ContentTemplate.) Многие элементы управления упаковывают

специфический, ограниченный тип содержимого (вроде строки текста в 

текстовом поле). Поскольку эти элементы управления не поддерживают

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

содержимым

UserControl

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

сконфигурирован с применением поверхности времени проектирования. Хотя

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

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

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

пользовательского интерфейса в более чем одном окне (вместо создания

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

перенесен из одного приложения в другое)

ItemsControl или 

Selector

itemsControl — базовый класс  для элементов управления, 

служащих оболочками для  списков элементов, но не поддерживающих выбор 

позиций, в то время как Selector — более специализированный 

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

применяются для создания пользовательских элементов управления,

поскольку средства шаблонов данных ListBox, ListView и TreeView

обеспечивают достаточную  гибкость

Panel

Базовый класс для элементов  управления, обладающих логикой 

компоновки. Элемент с  компоновкой может содержать  в себе множество 

дочерних элементов и  размещать их в соответствии с  определенной 

семантикой компоновки. Часто  панели включают присоединенные свойства,

которые могут быть установлены  в дочерние элементы для того, чтобы 

конфигурировать их расположение

Decorator

Это базовый класс для  элементов, служащих оболочками для  других 

элементов и обеспечивающих графический эффект или определенное 

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

линию вокруг элемента, и Viewbox, масштабирующий свое содержимое

динамически с использованием трансформаций. Среди других 

декораций — классы Chrome, служащие для снабжения знакомыми  рамками и 

фоном часто используемых элементов управления, таких как  кнопка

Специфический класс элемента управления

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

проверки достоверности (что будет продемонстрировано далее  в настоящей 

главе). Однако прежде чем  предпринять такой шаг, подумайте, нельзя ли

достичь той же цели с  помощью кода обработки событий  или отдельного

компонента. Оба подхода  позволят отделить логику от элемента 

управления и применять  ее в других элементах


 

Рис. 1. Базовые классы простых  элементов и элементов управления

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

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

Создание указателя цвета  достаточно просто. В Интернете доступно несколько примеров такого инструмента, в том числе один в комплекте .NET Framework SDK. Тем не менее, создание собственного инструмента для выбора цвета остается полезным упражнением. Оно не только позволяет продемонстрировать широкое разнообразие важных концепций построения элементов управления, но также предоставляет практичный кусок функциональности.

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

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

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

Определение свойств  зависимости

Первый шаг в создании указателя цвета — добавление пользовательского элемента управления в проект библиотеки элементов управления. Когда это делается, Visual Studio создает  файл разметки XAML и соответствующий  специальный класс, чтобы определить в них инициализацию и код  обработки событий. Это то же самое, что приходится делать при создании нового окна или страницы. Единственное отличие в том, что контейнером  верхнего уровня выступает класс UserControl:

public partial class ColorPicker : System.Windows.Controls.UserControl

{ ... }

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

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

Как известно, первый шаг  в создании свойства зависимости  — это определение статического поля для него с добавленным словом Property в конце его имени:

public static DependencyProperty ColorProperty;

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

public static DependencyProperty RedProperty;

public static DependencyProperty GreenProperty;

public static DependencyProperty BlueProperty;

Хотя свойство Color будет хранить объект System.Windows.Media.Color, свойства Red, Green и Blue будут хранить индивидуальные байтовые значения, представляющие каждый из трех компонентов цвета. (Можно также добавить ползунок и свойство для установки альфа-значения, что позволит создавать частично прозрачные цвета, но в данном примере это не делается.)

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

В указателе цвета нужно  сделать только одно — добавить обратные вызовы, которые будут реагировать  на изменение различных свойств. Это объясняется тем, что свойства Red, Green и Blue — на самом деле просто другое представление свойства Color, и при изменении любого из этих трех следует обеспечить синхронизацию  последнего.

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

static ColorPicker()

        {

            // Регистрация свойств зависимости

            ColorProperty = DependencyProperty.Register("Color", typeof(Color), typeof(ColorPicker),

                new FrameworkPropertyMetadata(Colors.Black, new PropertyChangedCallback(OnColorChanged)));

            RedProperty = DependencyProperty.Register("Red", typeof(byte), typeof(ColorPicker),

                new FrameworkPropertyMetadata(new PropertyChangedCallback(OnColorRGBChanged)));

            GreenProperty = DependencyProperty.Register("Green", typeof(byte), typeof(ColorPicker),

                new FrameworkPropertyMetadata(new PropertyChangedCallback(OnColorRGBChanged)));

            BlueProperty = DependencyProperty.Register("Blue", typeof(byte), typeof(ColorPicker),

                 new FrameworkPropertyMetadata(new PropertyChangedCallback(OnColorRGBChanged)));

         }

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

public Color Color

{

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

      set { SetValue(ColorProperty, value); }

}

public byte Red

{

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

      set { SetValue(RedProperty, value); }

}

public byte Green

{

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

      set { SetValue(GreenProperty, value); }

}

public byte Blue

{

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

      set { SetValue(BlueProperty, value); }

}

Вспомните, что оболочки свойств не должны содержать никакой  логики, поскольку свойства могут  устанавливаться и извлекаться  непосредственно с помощью методов SetValue() и GetValue() базового класса DependencyObject. Например, логика синхронизации свойств в данном примере реализуется с использованием обратных вызовов, которые инициируются при изменении свойств через их оболочки, либо при прямом вызове SetValue().

Обратные вызовы изменения  свойств отвечают за сохранение соответствия свойства Color текущим значениям Red, Green и Blue. Всякий раз, когда изменяется свойство Red, Green или Blue, свойство Color тоже соответствующим  образом модифицируется:

private static void OnColorRGBChanged(DependencyObject sender,

            DependencyPropertyChangedEventArgs e)

        {

            ColorPicker colorPicker = (ColorPicker)sender;

            Color color = colorPicker.Color;

            if (e.Property == RedProperty)

                color.R = (byte)e.NewValue;

            else if (e.Property == GreenProperty)

                color.G = (byte)e.NewValue;

            else if (e.Property == BlueProperty)

                color.B = (byte)e.NewValue;

        }

В случае установки свойства Color свойства Red, Green и Blue также обновляются:

private static void OnColorChanged(DependencyObject sender,

      DependencyPropertyChangedEventArgs e)

{

      Color newColor = (Color)e.NewValue;

      ColorPicker colorpicker = (ColorPicker)sender;

      colorpicker.Red = newColor.R;

      colorpicker.Green = newColor.G;

      colorpicker.Blue = newColor.B;

}

Хотя на первый взгляд может  показаться, что такой код инициирует бесконечную последовательность вызовов, когда каждое свойство будет изменять другое, на самом деле подобного  не происходит. Это объясняется тем, что WPF не допускает повторного вхождения при обратных вызовах изменения свойств. Например, при изменении свойства Color инициируется метод OnClolorChanged(). Он модифицирует свойства Red, Green и Blue, генерируя три раза обратный вызов OnColorRGBChanged() (по одному для каждого из свойств). Однако OnColorRGBChanged() не вызовет еще раз OnClolorChanged().

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

Информация о работе WPF: пользовательские элементы