Элемент Control в WinRT

164

Ранее я обозначил различие между классами, производными от FrameworkElement, и классами, производными от Control. Первые (например, TextBlock и Image) я называл «элементами», чтобы сохранить разделение этих двух категорий но сейчас требуется более глубокое объяснение.

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

С другой стороны, элементы не обделены средствами формирования макета, применения стилей или привязки данных. Класс FrameworkElement определяет такие макетные свойства, как Width, Height, HorizontalAlignment, VerticalAlignment и Margin, а также свойство Style и метод SetBinding.

Особенности Control

С точки зрения визуальной и функциональной классы, производные от FrameworkElement, представляет собой примитивы (атомы, если можно так выразиться), тогда как классы, производные от Control, представляют собой результат компоновки этих примитивов (молекулы в нашей аналогии). Объект Button обычно строится из Border и TextBlock; объект Slider состоит из пары элементов Rectangle и объекта Thumb, который сам является элементом управления - вероятно, построенным из Rectangle. Все, что имеет визуальное содержимое (помимо текста, растровой или векторной графики), почти наверняка является классом, производным от Control.

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

Например, визуальное переопределение кнопки (Button) может потребоваться в том случае, если кнопка должна быть круглой, а не прямоугольной. Визуальное переопределение TextBlock или Image не имеет смысла, потому что они не содержат ничего, кроме текста или графики. Чтобы добавить что-то свое в TextBlock или Image, следует определить Control; тем самым вы создаете визуальное дерево, включающее примитив элемента. И хотя вы можете определить класс, производный от FrameworkElement, вряд ли вам удастся сделать что-то с результатом. К нему невозможно применить визуальное Но если определить класс, производный от Control, вы сможете настроить внешний вид своего элемента управления, определив визуальное дерево в XAML.

Класс Control определяет набор свойств, которые он сам не использует. Эти свойства предназначены для классов, производных от Control, и относятся они в основном к TextBlock (CharacterSpacing, FontFamily, FontSize, FontStretch, FontStyle, FontWeight и Foreground) и Border (Background, BorderBrush, BorderThickness и Padding). He каждый класс, производный от Control, содержит текст или рамку, но если эти свойства понадобятся вам при создании нового элемента управления или нового шаблона для существующего элемента управления - они к вашим услугам. Класс Control также предоставляет два новых свойства с именами HorizontalContentAlignment и VerticalContentAlignment для определения визуального оформления элементов управления.

Классы, производные от Control, часто определяют новые свойства и события. Часто они обрабатывают события пользовательского ввода от мыши, пера и клавиатуры и преобразуют их во входные данные событий более высокого уровня. Например, класс ButtonBase (базовый для всех классов кнопок) определяет событие Click. Класс Slider определяет событие ValueChanged, сообщающее об изменении свойства Value. Класс TextBox определяет событие TextChanged, которое сообщает об изменении свойства Text.

В реальной жизни классы, производные от Control, чаще взаимодействуют с пользователями. Для удобства работы с входными данными пользователей Control предоставляет защищенные виртуальные методы, соответствующие всем событиям пользовательского ввода, определяемым UIElement. Например, UIElement определяет событие Tapped, a Control определяет защищенный виртуальный метод OnTapped(). Control также определяет свойство IsEnabled, чтобы элемент управления не принимал ввод пользователя в ситуации, в которой этот ввод неприменим, и определяет событие IsEnabledChanged, которое срабатывает при изменении этого свойства. Это единственное открытое событие, фактически определяемое в Control.

Идея «фокуса ввода» у элементов управления остается актуальной в Windows 8. Когда элемент управления обладает фокусом ввода, пользователь ожидает, что этот конкретный элемент управления будет получать большую часть событий клавиатуры. (Конечно, некоторые события клавиатуры - например, нажатие клавиши Windows - выходят за пределы фокуса ввода.) Для этой цели класс Control определяет метод Focus(), а также виртуальные методы OnGotFocus() и OnLostFocus().

Концепция фокуса ввода с клавиатуры связана с концепцией перехода между элементами управления при помощи клавиши Tab. Для этого класс Control определяет свойства IsTabStop, TabIndex и TabNavigation.

Многие классы, производные от Control, находятся в пространстве имен Windows.UI.Xaml.Controls, но некоторые из них размещаются в пространстве имен Windows.UI.Xaml.Controls.Primitives. Последнее обычно резервируется для элементов управления, используемых в составе других элементов управления, но это всего лишь рекомендация, а не требование.

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

Object
    DependencyObject
        UIElement
            FrameworkElement
                Control
                    ContentControl
                    ItemsControl
                    RangeBase
                    UserControl

Класс ContentControl (базовый для таких важных классов, как Button, ScrollViewer и AppBar) на первый взгляд не делает почти ничего, кроме определения свойства Content типа object. Например, для Button свойству Content задается то содержимое, которое должно отображаться внутри Button. Чаще всего это текст или растровое изображение, но может быть и панель с другим содержимым.

Интересно, что свойство Content класса ContentControl имеет тип object вместо UIElement. Этому есть причина. В содержимом Button можно разместить практически любой тип объекта, в том числе и шаблон (в форме визуального дерева), который сообщает Button, как следует выводить содержимое. Для Button эта возможность используется не так часто, но для других классов, производных от ItemsControl, ее важность возрастает.

ItemsControl - родительский класс для элементов управления, предназначенных для вывода коллекций объектов. К этой категории принадлежат как знакомые классы ListBox и ComboBox, так и новые элементы управления Windows 8 - FlipView, GridView и ListView.

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

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

Пройди тесты
Лучший чат для C# программистов