Элемент ContentControl
87Silverlight 5 --- Элемент ContentControl
Элементы, наследующие класс ContentControl — это специальный тип элементов управления, которые могут содержать только один вложенный элемент. Этим они отличаются от контейнеров, способных содержать произвольное количество вложенных элементов.
Все контейнеры Silverlight наследуют класс Panel, предоставляющий им возможность содержать много элементов. В то же время все элементы, способные содержать только один элемент, наследуют класс ContentControl. Иерархия классов показана на следующей диаграмме:
Как видно, несколько самых популярных элементов управления фактически являются элементами ContentControl, включая ToolTip, Button, RadioButton и CheckBox. Есть также специальные элементы ContentControl, такие как ScrollViewer. Некоторые элементы ContentControl предназначены для использования с другими, специальными элементами. Например, элемент ListBoxItem должен быть вложен в ListBox.
Свойство Content
Обратите внимание на то, что в классе Panel определена коллекция Children, содержащая вложенные элементы, а в классе, наследующем ContentControl, определено свойство Content, содержащее один объект. Свойство Content может содержать объект любого типа, благодаря чему существуют три способа вывода содержимого:
Элементы. Если в качестве содержимого класса ContentControl используется элемент, наследующий класс UIElement, этот элемент выводится на экран.
Другие объекты. Если поместить в свойство Content объект, не являющийся элементом, будет вызван метод ToString(), возвращающий текстовое представление объекта. Для многих типов объектов метод ToString() возвращает вполне осмысленное текстовое представление. Для других он возвращает полностью квалифицированное имя класса, которому принадлежит объект.
Другие объекты с шаблонами данных. Если поместить в свойство Content объект, не являющийся элементом, и присвоить шаблон данных свойству ContentTemplate, элемент ContentControl выведет шаблон данных и применит определенные в нем выражения для извлечения данных из свойств других объектов. Этот способ полезен при работе с коллекциями объектов данных.
Рассмотрим простую кнопку. Для генерации ее содержимого достаточно простой текстовой строки:
<Button Margin="5" Content="Простая кнопка"/>
Однако в кнопку можно поместить и другие, более сложные элементы. Например, с помощью класса Image в кнопку можно поместить изображение:
<Button Margin="5">
<Image Source="myimage.png" Stretch="None"/>
</Button>
В кнопку можно также поместить изображение и текст, заключив их в какую-либо оболочку, например в контейнер StackPanel.
Для создания еще более экзотической кнопки в нее можно добавить другие элементы ContentControl, например текстовые поля и другие кнопки (кнопка в кнопке!). Вряд ли существуют ситуации, в которых это необходимо, но это возможно.
Какие преимущества предоставляют элементы ContentControl по сравнению с обычными? Ведь в кнопку можно поместить изображение. Не достаточно ли этого? Однако модель вложения содержимого все же имеет ряд важных преимуществ.
В предыдущем примере в кнопку было добавлено растровое изображение. Но это лишь простейший пример. Более гибкий интерфейс можно спроектировать, создав векторное изображение на основе фигур Silverlight. Тогда кнопку можно будет масштабировать и модифицировать программно, изменяя цвет или применяя анимацию. Использование векторных кнопок открывает возможности создания динамических интерфейсов, реагирующих на действия пользователя и ситуацию в приложении.
Модель векторных изображений плавно интегрируется в модель вложенного содержимого элементов ContentControl, поскольку они могут содержать любые элементы. Например, приведенная ниже разметка создает простую графическую кнопку, содержащую векторное изображение:
<Button Margin="5" Height="100" Width="100" Background="DarkOrange">
<Grid>
<Path Stretch="Fill" Stroke="LimeGreen" Fill="LimeGreen"
Data="F1 M 23.25,9.10939C 23.25,13.1094 21.5,16.8594 21.5,15.8594C 21.5,14.8594 19.5,18.8594
18.5,20.8594C 17.5,22.8594 16.5,25.6094 16.5,25.6094L 12.5,25.3594C 12.5,25.3594 11.5,34.1094
13.5,35.1094C 15.5,36.1094 17.5826,34.7089 19.5,35.8594C 24.5,38.8594 32.5,36.8594 31.5,34.8594C
31.5,34.8594 35.5,32.8594 34.5,31.8594C 34.5,31.8594 35.5,30.3594 34.25,28.8594C 35.5,27.3594
35,25.8594 34.25,24.8594C 35,23.3594 35.5,21.8594 32.5,20.8594C 30.6026,20.2269 25.5,22.6094
25.5,19.8594C 25.5,18.8594 27.5,15.8594 27.5,13.8594C 27.5,9.85939 23.25,9.10939 23.25,9.10939 Z"/>
</Grid>
</Button>
Вполне очевидно, что в данном случае проще применить модель вложенного содержимого, чем добавить в класс Button дополнительные свойства, поддерживающие разные типы содержимого. Модель вложенного содержимого не только проще, она еще и позволяет классу Button содержать более гибкое содержимое. Все элементы ContentControl поддерживают вложение содержимого одним и тем же способом, поэтому нет необходимости добавлять разные свойства содержимого в разные классы.
В сущности, модель вложенного содержимого — это вынужденный компромисс. Она упрощает модель классов тем, что устраняет необходимость использования дополнительных слоев наследования для добавления свойств для разных типов содержимого. Однако она же приводит к необходимости использовать более сложную объектную модель построения элементов на основе других вложенных элементов.
Нужный эффект всегда можно получить, изменив содержимое элемента управления. Например, несмотря на то что в кнопку можно поместить любое содержимое, некоторые эффекты кнопки все же невозможно создать. К ним относятся затенение фона, изменение радиуса скругления рамки, подсвечивание кнопки при наведении на нее указателя и др. Однако эти эффекты можно создать другим способом: применив шаблон элемента управления.
Выравнивание содержимого
Выравнивание содержимого выполняется с помощью свойств HorizontalContentAlignment и VerticalContentAlignment.
Для свойств HorizontalContentAlignment и VerticalContentAlignment доступны те же значения, что и для HorizontalAlignment и VerticalAlignment. Это означает, что содержимое можно выровнять по одному из краев рамки (значения Top, Bottom, Left и Right), центрировать (значение Center) или растянуть, пока оно не заполнит доступное пространство (значение Stretch).
Эти значения применяются непосредственно к вложенному содержимому, но можно также создать много уровней вложения для реализации сложной визуальной структуры. Например, если контейнер StackPanel вложен в элемент Button, свойство Button.HorizontalContentAlignment определяет лишь, где расположен элемент StackPanel, а остальные параметры визуальной структуры определяются свойствами выравнивания и установки размеров контейнера StackPanel и его дочерних элементов.
В элементах управления используется дополнительное свойство Padding, добавляющее внутренний отступ между границей элемента управления и содержимым.
Свойства HorizontalContentAlignment, VerticalContentAlignment и Padding определены в классе Control, а не в специальном классе ContentControl. Это объясняется тем, что некоторые элементы управления не наследуют класс ContentControl, но все же могут иметь содержимое. Один из примеров такого элемента управления - текстовое поле TextBox. Для включенного в него текста, определяемого свойством Text, нужно каким-либо образом задавать выравнивание и ширину внутренних отступов. Это делается с помощью указанных выше свойств.