Элементы управления содержимым

69

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

Конечно, есть способ поместить в один элемент управления содержимым много различного содержимого — для этого нужно упаковать все в один контейнер, такой как StackPanel или Grid. Например, сам класс Window является элементом управления содержимым. Понятно, что окна обычно содержат много всякого содержимого, но все оно упаковано в один контейнер высокого уровня (обычно Grid).

Все контейнеры компоновки WPF порождены от абстрактного класса Panel, который обеспечивает содержание нескольких элементов. Аналогично, все элементы управления содержимым порождены от абстрактного класса ContentControl. Иерархия классов приведена на рисунке:

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

Как показано на рисунке, некоторые распространенные элементы управления на самом деле являются элементами управления содержимым — к ним относятся, например, Label и ToolTip. Кроме того, все виды кнопок являются элементами управления содержимым, в том числе привычные Button, RadioButton и CheckBox. Существуют и более специализированные элементы управления, такие как ScrollViewer (позволяет создать прокручиваемую панель) и UserControl (позволяет повторно использовать пользовательскую группировку элементов управления). Даже класс Window, предназначенный для отображения всех окон приложения, сам является элементом управления содержимым.

И, наконец, имеется подмножество элементов управления содержимым, которое проходит через дополнительный уровень наследования — они порождены от класса HeaderedContentControl. Эти элементы имеют и область содержимого, и область заголовка, где можно выводить какую-то заглавную информацию. К ним относятся элементы GroupBox, TabItem (страница в TabControl) и Expander.

На рисунке не показано несколько элементов. Там нет элемента Frame, предназначенного для навигации, и нескольких элементов, которые применяются внутри других управляющих элементов (такие как текстовая панель и строка состояния).

Свойство Content

Аналогично тому, как класс Panel добавляет коллекцию Children для хранения вложенных элементов, класс ContentControl добавляет свойство Content, которое принимает единственный объект.

Свойство Content поддерживает объекты любых типов, но разделяет их на две группы и обрабатывает эти группы по-разному:

Объекты, не порожденные от UIElement

Элементы управления содержимым получают текст из таких элементов с помощью метода ToString(), а затем выводят этот текст.

Объекты, порожденные от UIElement

Эти объекты (к которым относятся все визуальные элементы, входящие в WPF) выводятся внутри элемента управления содержимым с помощью метода UIElement.OnRender().

Ниже представлен пример, в котором кнопки имеют содержимое различных типов:

<Grid>
        <StackPanel MinWidth="250">
            <Button Margin="5" Padding="5">Text button</Button>
            <Button Margin="5,0,5,5" Padding="3">
                <Image Source="grimace.png" Width="40"></Image>
            </Button>
            <Button Margin="5,0,5,0">
                <StackPanel>
                    <TextBlock>Text and Image Button</TextBlock>
                    <Image Source="grimace.png" Width="40"></Image>
                    <TextBlock>Кнопка имеет смешанное содержимое</TextBlock>
                </StackPanel>
            </Button>
            <Button Margin="5">
                <StackPanel Width="265">
                    <TextBlock Margin="3">Some Button</TextBlock>
                    <TextBox Margin="3,2,7,3" MinHeight="24" FontSize="15" FontFamily="Vivaldi">
                        Some Text in my Button
                    </TextBox>
                </StackPanel>
            </Button>
        </StackPanel>
</Grid>
Различное вложенное содержимое в кнопках

Текстовое содержимое можно размещать внутри элемента управления содержимым, т.к. синтаксический анализатор XAML преобразовывает его в строковый объект и использует для задания свойства Content. Однако строковое содержимое нельзя поместить непосредственно в компоновочный контейнер. Его нужно сначала упаковать в класс, порожденный от UIElement — например, TextBlock или Label.

А если вам захочется создать ну совсем уж экзотическую кнопку, можно поместить на нее и другие элементы управления содержимым: текстовые поля и даже другие кнопки (которые также могут содержать другие вложенные элементы). Вряд ли подобный интерфейс когдалибо пригодится, но это возможно.

Это та же модель содержимого, которая применяется для окон. Как и класс Button, класс Window допускает наличие одного вложенного элемента, который может быть текстом, произвольным объектом или элементом управления.

Одним из немногих элементов, которые не разрешены внутри элементов управления содержимым, является Window. Окно при создании проверяет, является ли оно контейнером самого верхнего уровня. Если оно размещено в другом элементе, объект Window генерирует исключение.

Кроме свойства Content, класс ContentControl не содержит почти ничего нового. В нем имеется свойство HasContent, которое возвращает true при наличии в элементе содержимого, и ContentTemplate, которое позволяет создать шаблон, указав элементу, как нужно отображать нераспознанный объект. Класс ContentTemplate позволяет более осмысленно выводить объекты, порожденные не от UIElement. Пользуясь значениями различных свойств, можно, вместо простого вызова ToString() для получения строки, организовать их в более сложную разметку.

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