Модель содержимого элементов управления

87

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

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

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

В частности, можно определить элемент управления типа Button с оживляемой стрелкой и отображаемым фрагментом текста в качестве содержимого. Для определения сложного внутреннего содержимого в среде Expression Blend IDE предоставляются соответствующие инструменты, хотя их применение в подобных целях может оказаться не вполне очевидным. Для того чтобы разобраться в этом вопросе, начните, как всегда, с создания нового проекта приложения WPF, присвоив ему имя BlendControlContent.

Найдите на панели Tools или в библиотеке ресурсов элемент управления типа Button и расположите один его экземпляр у верхнего края монтажного стола визуального конструктора главного окна (объекта типа Window). Как только вы выберете этот элемент управления на монтажном столе, в области Common Properties на панели Properties появится текстовое поле свойства Content, где можно ввести простой текст:

Задание простого содержимого на панели Properties

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

Создание составного содержимого

Подробнее о работе с диспетчерами компоновки речь пойдет в следующих статьях, а пока найдите элемент управления типа StackPanel в библиотеке ресурсов (напомним, что интересующий вас элемент можно быстро найти, введя его имя в поле поиска Search). Дважды щелкните на нем, чтобы добавить его в главное окно приложения, представленное объектом типа Window. Затем перетащите его на элемент управления типа Button и нажмите клавишу <Alt>. В итоге объект типа StackPanel окажется в области действия элемента управления Button и будет использоваться для хранения нового составного содержимого.

Составное содержимое

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

В настоящий момент совершенно очевидно, что размеры встроенного диспетчера компоновки нужно увеличить, чтобы охватить им внутреннюю часть элемента управления. Это можно сделать инструментом обычного выделения Selection, доступным на панели Tools с помощью кнопки, обозначенной пиктограммой черной стрелки. В рассматриваемом здесь примере требуется расположить по горизонтали, а не по вертикали данные, хранящиеся в StackPanel. С этой целью установите в его свойстве Orientation - Horizontal.

Если вы теперь перейдете к панели Objects and Timeline, то сможете выбрать диспетчер компоновки элемента управления типа Button, т.е. объект типа StackPanel, а затем добавить любое количество дополнительных компонентов. Итак, добавьте выбранную вами геометрическую форму, например эллипс, звезду или стрелку, а также элемент управления типа Label в данный диспетчер компоновки, например:

Иерархическое представление внутреннего содержимого

Теперь можете выбрать каждый компонент для последующей правки. Как показано на рисунке ниже, некоторые основные свойства объекта типа Label, обозначающего метку, были изменены на панели Properties, в том числе размер шрифта в области Text, расположение текста в области Layout, а также текст ОК! самой метки в свойстве Content. Кроме того, для обводки по контуру и заполнения внутренней части формы звезды нужными цветами были специально настроены соответствующие кисти:

Необычный вид кнопки

Но самое интересное, что для рассматриваемого здесь элемента управления была создана анимация изменения цвета звезды в течение одной секунды, при условии, что объект типа Button находится в оперативной памяти. Для этой цели было активизировано свойство AutoReverse, а в свойстве RepeatBehavior установлено значение Forever. Для того чтобы не повторять снова все особенности работы с редактором анимации, подробно рассматриваемые ранее, приведем лишь самые основные этапы создания раскадровки новой анимации:

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

При создании элемента управления с составным содержимым можно по желанию организовать обработку событий, наступающих для любых подчиненных компонентов. В частности, для компонента в форме звезды, представленного объектом типа RegularPolygon, можно обрабатывать событие MouseDown, наступающее при нажатии кнопки мыши, а для самой кнопки — событие Click. Подобным образом удается зафиксировать факт щелчка не только на кнопке вообще, но и на отдельных частях ее составного содержимого. Ниже приведен исходный код некоторых обработчиков упомянутых выше событий, при наступлении которых в главном окне приложения выводится сообщение в зависимости от того, где именно был произведен щелчок:

private void regularPolygon_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
		{
			this.Title = "Вы кликнули по звездочке!";
			e.Handled = true;
		}

		private void Button_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
		{
			this.Title = "Вы кликнули по кнопке!";
		}

В приведенном выше коде обратите внимание на следующее: при выполнении щелчка кнопкой мыши исключается распространение события по дереву разметки XAML благодаря установке логического значения true в свойстве Handled (Обработано) наступающего события, передаваемого обработчику событий в качестве аргумента. Если этого не сделать, событие от мыши будет сначала обработано на уровне формы звезды а затем на уровне самой кнопки. Но в любом случае запустите свое приложение на выполнение, нажав функциональную клавишу <F5>, чтобы проверить, будет ли кнопка реагировать на щелчки кнопкой мыши предполагаемым образом.

Повторное использование составного содержимого

Проанализировав разметку, автоматически сформированную в коде XAML, вы обнаружите, что элемент управления типа Button определен в ней предполагаемым образом. При этом диспетчер компоновки типа StackPanel определяет непосредственное содержимое данного элемента управления и сам содержит два элемента:

<Button Margin="212,141,288,0" VerticalAlignment="Top" Height="48.277" 
		        HorizontalContentAlignment="Left" MouseDown="Button_MouseDown">
	<StackPanel Orientation="Horizontal">
				<ed:RegularPolygon x:Name="regularPolygon" Fill="#FFF4F4F5" 
				                   Height="32.667" InnerRadius="0.47211" PointCount="5" Stretch="Fill" 
								   Stroke="#FFF10F0F" Width="32.667" StrokeThickness="2" 
								   MouseDown="regularPolygon_MouseDown"/>
				<Label Content="OK!" VerticalContentAlignment="Center" Padding="10,5" 
				       FontFamily="Tekton Pro Ext" FontWeight="Bold" FontSize="18.667" 
					   Width="70.47" HorizontalContentAlignment="Center"/>
	</StackPanel>
</Button>

Но при создании анимации в среде Expression Blend IDE ее раскадровка вводится в виде именованного ресурса объекта типа Window или объекта типа UserControl. Проанализировав разметку, описывающую анимацию, вы непременно обнаружите, что объекты, содержащиеся в специальной кнопке, упоминаются в этой разметке прямо по имени, как, например, объект regularPolygon, обозначающий форму звезды в составном содержимом данной кнопки:

<Window.Resources>
		<Storyboard x:Key="ColorStarAnimation" AutoReverse="True" RepeatBehavior="Forever">
			<ColorAnimationUsingKeyFrames Storyboard.TargetProperty="(Shape.Stroke).(SolidColorBrush.Color)" Storyboard.TargetName="regularPolygon">
				<EasingColorKeyFrame KeyTime="0" Value="#FFF10F0F"/>
				<EasingColorKeyFrame KeyTime="0:0:2" Value="#FF0F27F1"/>
			</ColorAnimationUsingKeyFrames>
		</Storyboard>
	</Window.Resources>

Аналогичным образом в разметке для ооъекта типа window описывается триггер, запускающий анимационную последовательность. По существу, рассматриваемая здесь специальная кнопка действует довольно обособленно. И в связи с этим возникает следующий вопрос - что, если в пользовательском интерфейсе потребуются три специальные кнопки с формой звезды?

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

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

А до тех пор просто запомните, что в большинстве элементов управления на платформах WPF и Silverlight поддерживается составное содержимое. Такое содержимое можно сформировать в среде Expression Blend IDE, введя в его пределы диспетчер компоновки и заполнив связанными элементами. С данным вопросом тесно связано понятие рассматриваемой далее модели содержимого многокомпонентных элементов управления.

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