Методология синхронной разработки приложения в Microsoft Visual Studio 2010

Стили и шаблоны элементов управления WPF

Показывать лекцию целиком

Цель лекции: получить знания о стилях и шаблонах. Научить создавать и повторно использовать шаблон Control’а. Задавать шаблон через стиль.

В Windows Presentation Foundation существует очень четкое разделение между поведением Control'а и тем, как он выглядит. К примеру, поведение объекта класса Button состоит в том, чтобы реагировать на различные события по клику, но его вид может быть любым — вы можете сделать кнопку в виде стрелки, рыбы, или чего-либо еще, что подходит для вашего приложения. Переопределение отображения Control'а очень просто сделать стилями и шаблонами. В WPF стилизация и использование шаблонов относятся к набору функций (стилей, шаблонов, триггеров и раскадровок), позволяющих разработчикам и дизайнерам создавать визуально привлекательные эффекты, а также создавать целостный внешний вид своих продуктов. Несмотря на то, что разработчики и дизайнеры могут настроить внешний вид в масштабе приложений, для обслуживания и синхронного использования внешнего вида внутри приложений и между приложениями необходима строгая модель стилей и шаблонов. WPF предоставляет такую модель.

Другая функция модели стилизации WPF состоит в разделении представления и логики. Это означает, что дизайнеры могут создавать внешний вид приложения, используя только XAML, в то же самое время, когда разработчики работают над логикой программы, используя C# или Visual Basic.

Стили

Стиль – это совокупность значений свойств, которые можно все сразу применить к нужному элементу. В Silverlight стили позволяют разгрузить вашу XAML разметку путем вынесения деталей форматирования элемента в отдельный блок. Система Silverlight стилей играет ту же роль, что и стандарт каскадных таблиц стилей (CSS) в HTML-верстке. Как и CSS, стили в Silverlight позволяют вам определять базовый набор характеристик форматирования и использовать их в вашем приложении для обеспечения согласованности. Но есть и несколько важных ограничений. Например, вы не сможете применить один стиль к элементам разных типов или назначить автоматическое использование стиля. По этой причине стили кажутся несколько неудобными, хотя и являются одной из ключевых возможностей.

Создание стиля

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

<UserControl.Resources>
    <Style x:Key="BigButtonStyle" TargetType="Button">
        ...
    </Style>
</UserControl.Resources>

У стиля, как и у всех ресурсов, имеется имя-ключ, по которому вы можете к нему обращаться. В нашем примере имя ключа – BigButtonStyle. (Обычно принято добавлять к именам стилей окончание "Style"). Кроме того, для любого Silverlight стиля должно быть задано поле TargetType, определяющее тип элементов, к которым может применяться данный стиль. В нашем случае стиль создается для форматирования кнопок (Button).

Наш объект Style содержит коллекцию сеттеров (setter) состоящую из 6-ти Setter-объектов (по одному на каждое свойство). Каждый сеттер описывает только одно свойство элемента. Единственным ограничением является то, что сеттер способен изменять только зависимые свойства (dependency properties), и никакие другие. Но, как показывает практика, это не такое уж и большое ограничение, поскольку почти все свойства Silverlight элементов – зависимые свойства. Сеттеры свойств могут влиять на любые зависимые свойства, даже на те, что управляют поведением объекта, а не его внешним видом. К примеру, если вы применяете стиль к текстовому полю, можете выставлять параметры AcceptsReturn и IsReadOnly непосредственно в самом стиле.

Перед вами стиль большой кнопки с белым текстом шрифта Georgia на темном фоне:

<UserControl.Resources>
    <Style x:Key="BigButtonStyle" TargetType="Button">
        <Setter Property="FontFamily" Value="Georgia" />
        <Setter Property="FontSize" Value="40" />
        <Setter Property="Foreground" Value="SlateGray" />
        <Setter Property="Background" Value="Black" />
        <Setter Property="Padding" Value="20" />
        <Setter Property="Margin" Value="10" />
    </Style>
</UserControl.Resources>

В некоторых случаях вы не сможете задать значение свойства, используя простой формат записи атрибута. Например, простая запись не позволяет создавать неоднородную кисть LinearGradientBursh или ImageBrush. В такой ситуации вы можете применить уже знакомый для XAML прием замещения атрибута каким-либо вложенным элементом. Вот пример:

<Style x:Key="BigButtonStyle" TargetType="Button">
    <Setter Property="Background">
        <Setter.Value>
            <LinearGradientBrush StartPoint="0,0" EndPoint="1,0">
                <GradientStop Color="Blue"></GradientStop>
                <GradientStop Color="Yellow" Offset="1"></GradientStop>
            </LinearGradientBrush>
        </Setter.Value>
    </Setter>
    ...
</Style>

Использование стиля

Каждому элементу Silverlight можно задать только один стиль (или ни одного). Стиль встраивается в элемент через свойство стиля элемента (которое определено в базовом классе FrameworkElement). Например, чтобы применить к кнопке заранее созданный стиль, вы должны указать ресурс стиля, как в этом случае:

<Button
    Style="{StaticResource BigButtonStyle}"
    Content="A Customized Button"/>

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

На рис. 4.1 показана страница с двумя кнопками, использующими стиль BigButtonStyle.

(рис 4.1) Повторное использование настроек с применением стиля

Система стилей имеет много плюсов. Она не только позволяет вам создавать группы настроек с четкими связями, но и делает вашу XAML разметку более компактной благодаря простому способу подключения этих настроек. Но самое главное, вы можете применять стили, не заботясь об их внутреннем содержимом. В предыдущем примере настройки шрифта были описаны внутри стиля BigButtonSyle. Если спустя какое-то время вы решите увеличить величину значений свойств Padding и Margin, вы сможете просто добавить к описанию стиля соответствующие сеттеры свойств. Тогда новые настройки стиля автоматически вступят в силу для всех кнопок, использующих этот стиль.

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

Размещение стилей

В предыдущем примере стиль описан на уровне определенной страницы и затем использован для двух кнопок той же страницы. Хотя такая практика наиболее распространена, этот вариант размещения стиля не единственно возможный.

Собственно говоря, вы не обязаны объединять стили с ресурсами. Вы можете, к примеру, определить стиль отдельной кнопки, описав набор атрибутов стиля прямо в самой кнопке, как показано здесь:

<Button Content="A Customized Button">
    <Button.Style>
        <Style TargetType="Button">
            <Setter Property="FontFamily" Value="Georgia" />
            <Setter Property="FontSize" Value="40" />
            <Setter Property="Foreground" Value="White" />
            <Setter Property="Background" Value="Black" />
        </Style>
    </Button.Style>
</Button>

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

Будет более разумно, если вы решите описать стили в отдельном ресурсе. Если вы пожелаете создать более строго специализированные стили, вы можете описать их в ресурсах контейнера, например в StackPanel или в Grid (такие стили можно будет применять только к элементам, вложенным в этот контейнер). Более того, один и тот же стиль можно описать на нескольких уровнях сразу (в контейнере StackPanel, содержащем кнопку, и внутри страницы, содержащей этот StackPanel). В такой ситуации Silverlight следует стандартному процессу поиска имен: сначала он ищет в ресурсах текущего элемента, затем в контейнере содержащем этот элемент, затем в следующем контейнере уровнем выше, и т.д., пока не найдет стиль с соответствующим именем. Если вы хотите, чтобы стиль был доступен в любой части кода вашего приложения, опишите его в ресурсах приложения (в файле App.xaml), поиск в котором происходит в последнюю очередь.

Основы шаблонов

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

В Silverlight имеется куда более радикальный инструмент для настройки подобных вещей, называемый шаблонами (templates). Тогда как стили можно применять к любому Silverlight элементу, использование шаблонов ограничено Silverlight Control’ами, т.е. элементами, которые наследуются от класса Control, принадлежащего пространству имен System.Windows.Controls. У таких элементов имеется свойство Template, через которое вы можете задавать свой шаблон, и тем самым, перекрыть стандартное визуальное представление Control’а.

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

Шаблоны – это одна из наиболее сложных деталей в WPF, поэтому не удивительно, что в Silverlight все еще отсутствуют некоторые возможности. Более неожиданно то, что факт отсутствия этих возможностей создает условия, в которых Silverlight Control’ы вынуждены опираться на новый комплекс стандартов и использовать более продуманные правила проектирования шаблонов.

Создание шаблона

Каждый Control содержит встроенный набор правил, определяющий его отрисовку (в виде набора более простых элементов). Этот набор правил называется шаблоном Control’а (control template). Описывается он как блок XAML-разметки и применяется к Control’у через свойство "Template". Для примера давайте рассмотрим простую кнопку. Предположим, создавая пользовательский Control, вы пожелаете получить больше контроля над эффектами затенения и анимации кнопки. В этом случае первым делом нужно заменить существующий стандартный шаблон кнопки на свой собственный. Для того, чтобы создать шаблон кнопки, вам понадобится нарисовать свой бордюр кнопки, ее фон, а также предусмотреть размещение контента кнопки. На роль бордюра имеется несколько кандидатов, тут все зависит от того, какой корневой элемент вы выберите:

  • Бордюр (Border). Данный элемент решает две задачи: может содержать один элемент внутри себя (скажем TextBlock с заголовком кнопки), и отображать окаймляющий бордюр.
  • Таблица (Grid). Расположив несколько элементов в одном месте, вы можете создать кнопку с каемкой. Воспользуйтесь элементом формы (таким как Rectangle или Path) и в той же ячейке разместите TextBlock. Удостоверьтесь, что описание TextBlock’а в XAML идет после описания фигуры, поскольку текст должен быть наложен на фоновую фигуру, а не наоборот. Одно из достоинств контейнера Grid в том, что он поддерживает автоматический контроль размера, и вы можете быть уверены, что ваш Control будет всегда иметь размер, соответствующий размеру своего содержимого.
  • Канва (Canvas). В Canvas элементы могут размещаться строго по указанным координатам. В обычной ситуации это излишне, но может быть полезным, если вам требуется разместить несколько фигур особым образом относительно друг друга, например, при создании кнопки со сложным рисунком.
  • В следующем примере используется класс Border для сочетания закругленного оранжевого контура и броского красного фона с белым текстом:

    <Button Content="A Custom Button Template">
        <Button.Template>
            <ControlTemplate TargetType="Button" >
                <Border BorderBrush="Orange" BorderThickness="3" 
                        CornerRadius="10" Background="Red">
                    <TextBlock Foreground="White" Text="A Templated Button"/>
                </Border>
            </ControlTemplate>
        </Button.Template>
    </Button>

    На рисунке 4.2 вы видите результат:

    (рис 4.2) Очень простая кнопка

    Если вы попробуете использовать эту кнопку, то обнаружите, что данный шаблон слишком примитивен. Он лишен большей части признаков нормальной кнопки (например, визуального эффекта вдавливания в момент нажатия), и фактически игнорирует любое задаваемое свойство кнопки, даже самое основное - "Content". (Наш пример содержит жестко "вшитый" текст в TextBlock, так что команда "Content="A Custom Button Template"" тут только для вида.) Тем не менее, этот шаблон имеет все шансы стать настоящим шаблоном кнопки, и мы будем заниматься его доводкой в следующих параграфах.

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

    Повторное использование шаблона Control’а

    В предыдущем примере описание шаблона расположено внутри элемента. Однако гораздо чаще шаблон Control’а размещают отдельно, т.к. часто вы будете применять шаблон сразу к нескольким Control’ам. Шаблон можно поместить в ресурсы:

    <UserControl.Resources>
        <ControlTemplate x:Key="ButtonTemplate" TargetType="Button" >
            <Border BorderBrush="Orange" BorderThickness="3" CornerRadius="10" 
                    Background="Red">
                <TextBlock Foreground="White" Text="A Custom Template"/>
            </Border>
        </ControlTemplate>
    </UserControl.Resources>

    Затем в теге кнопки дописать ссылку на StaticResource:

    <Button Template="{StaticResource ButtonTemplate}"/>

    Такой подход не только упростит создание множества специализированных кнопок, но и позволит вам в будущем свободно модифицировать шаблон Control’а без необходимости изменять каждую кнопку, тем самым, уменьшая риск что-то испортить.

    Есть еще один вариант – вы можете вложить описание шаблона в описание стиля. Преимущество такого подхода в том, что стиль может сочетать сеттеры, устанавливающие другие свойства, с сеттером, определяющим новый шаблон Control’а. Применяя стиль к кнопке, вы задействуете все сеттеры. В результате ваша кнопка получит новый шаблон, а также все упомянутые в стиле значения свойств.

    ContentPresenter

    Кнопка из предыдущего примера довольно бесполезна, т.к. отображает только "вшитый" текст. Вы, конечно же, захотите иметь возможность задавать контент кнопки через свойство Button.Content. Для этого вам понадобится метка-заполнитель специального назначения – "ContentPresenter".

    ContentPresenter присутствует во всех Control’ах, содержащих какой-либо контент. Это специальная метка означающая "вставь контент здесь" и говорящая Silverlight, куда следует поместить содержимое Control’а. Вот как вы можете применить ее в нашем примере:

    <UserControl.Resources>
        <ControlTemplate x:Key="ButtonTemplate" TargetType="Button" >
            <Border BorderBrush="Orange" BorderThickness="3" CornerRadius="10" 
                    Background="Red">
                 <ContentPresenter/>
            </Border>
        </ControlTemplate>
    </UserControl.Resources>

    Замечание: ContentPresenter – наиболее востребованная, но не единственная метка. Control’ы представляющие списки и использующие ItemsControl применяют в своих шаблона метку ItemsPresenter, определяющую место, где должна располагаться панель списка элементов. Прокручиваемый контент Control’а ScrollViewer представлен меткой ScrollContentPresenter.

    Связывание в Шаблонах

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

    <Button Template="{StaticResource ButtonTemplate}" 
            Content="A Templated Button"
            Margin="10"
            Padding="20"/>

    В этой разметке свойствам кнопки Margin и Padding заданы значения 10 и 20 соответственно. За учет свойства Margin отвечает контейнер, содержащий кнопку, поэтому с этим проблем не возникает. Но свойство Padding не берется в расчет, поэтому края кнопки вплотную прилегают к ее контенту. Дело в том, что свойство Padding не будет иметь никакого эффекта, пока вы сами не позаботитесь об этом. Иначе говоря, именно ваш шаблон должен позаботиться о дополнительных отступах вокруг контента кнопки, величина которых задается в Padding.

    Для этой цели в Silverlight\WPF есть специальная возможность – связывание в шаблонах (template bindings). С помощью template binding шаблон Control’а сможет извлекать значения свойств Control’а, использующего данный шаблон. В следующем примере вы можете использовать template binding для получения значения свойства Padding и создания отступа вокруг ContentPresenter:

    <ControlTemplate x:Key="ButtonTemplate" TargetType="Button" >
        <Border BorderBrush="Orange"
                BorderThickness="3"
                CornerRadius="10"
                Background="Red">
            <ContentPresenter Margin="{TemplateBinding Padding}"/>
        </Border>
    </ControlTemplate>

    Теперь желаемый эффект получен и установлен некоторый зазор между текстом и краями кнопки. рис. 4.3 демонстрирует вашу новую скромную кнопку:

    (рис 4.3) Кнопка пользовательского шаблона Control’а

    Замечание: Связывание в шаблонах похоже на обычное связывание данных (data bindings), но весит гораздо меньше, поскольку предназначено специально для шаблонов и поддерживает только одностороннее связывание данных (другими словами, можно передать информацию от Control’а в шаблон, но не наоборот).

    Стало быть, вам придется добавить в ContentPresenter приличное количество элементов, если вы, конечно, хотите получить полноценную поддержку свойств класса Button и иметь возможность задавать такие свойства, как выравнивание, перенос текста, и т.д.. ControlPresenter в составе стандартного шаблона кнопок выглядит примерно так:

    <ContentPresenter
        HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
        Margin="{TemplateBinding Padding}" 
        VerticalAlignment="{TemplateBinding VerticalContentAlignment}" 
        Content="{TemplateBinding Content}" 
        ContentTemplate="{TemplateBinding ContentTemplate}"/>

    Связывание в шаблонах очень важно для свойства Content. Благодаря связыванию содержимое извлекается из Control’а и отображается в ContentPresenter. Зачастую можно не включать связывание для некоторых свойств шаблона, если вы не намерены их использовать.

    Замечание: Связывание в шаблонах поддерживает встроенную во все зависимые свойства инфраструктуру мониторинга изменений. Это значит, что если вы изменяете свойство Control’а, шаблон автоматически применяет его новое значение. Это особенно полезно, когда вы используете анимацию, многократно изменяющую значение свойства.

    Установка шаблонов через стили

    Связывание в шаблонах не ограничивается классом ContentPresenter. На самом деле вы можете использовать его в любом месте шаблона Control’а. Давайте рассмотрим наш пример кнопки с "вшитым" красным цветом фона элемента Border. Вот как можно использовать шаблонное связывание для управления фоном:

    <Border BorderBrush="Orange" 
            BorderThickness="3" 
            CornerRadius="10"
            Background="{TemplateBinding Background}">

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

    <Style x:Key="ButtonStyle" TargetType="Button">
        <Setter Property="Background" Value="Red"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="Button">
                    <Border BorderBrush="Orange" 
                            BorderThickness="3" 
                            CornerRadius="10"
                            Background="{TemplateBinding Background}">
                        <ContentPresenter Margin="{TemplateBinding Padding}"/>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

    Но можно оставить стиль отдельным ресурсом:

    <Style x:Key="ButtonStyle" TargetType="Button">
        <Setter Property="Background" Value="Red"/>
        <Setter Property="Template" Value="{StaticResource ButtonTemplate}"/>
    </Style>

    Только учтите, что в таком случае объявление стиля должно следовать после объявления шаблона.

    Синхронное использование стилей и шаблонов также бывает полезным, если вам нужно задать свойства (зависимые свойства), отсутствующие в ContentPresenter или в элементах контейнера вашего шаблона. Обратите внимание, что в нашем примере нет связывания для цвета шрифта кнопки. А все потому, что эти свойства (Foreground, FontFamily, FontSize, FontWeight, и т.д.) участвуют в наследовании свойств. Когда вы задаете эти значения в элементе более высокого уровня (например, в кнопке), они распространяются на вложенные элементы (например, TextBlock внутри кнопки). Сам же ContentPresenter не имеет этих свойств, и в этом нет необходимости. Значения этих свойств передаются от Control’а к вложенному контенту минуя ContentPresenter.

    Иногда вам может понадобиться изменить значение наследуемого свойства, чтобы ограничить изменение вида вашего Control’а. Например, в нашем случае важно, чтобы цвет текста был белым, поскольку белый текст лучше выделяется на красном фоне кнопки. Но стандартный цвет шрифта наследуется от Silverlight страницы, на которой расположены наши элементы, и этот цвет – черный. К тому же вы не можете установить цвет через ContentPresenter, т.к. он не содержит свойства Foreground. Для решения этой проблемы нужно объединить шаблон Control’а со стилем, сеттер которого задает белый цвет текста:

    <Style x:Key="ButtonStyle" TargetType="Button">
        <Setter Property="Foreground" Value="White"/>
        <Setter Property="Background" Value="Red"/>
        <Setter Property="Template" Value="{StaticResource ButtonTemplate}"/>
    </Style>

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

    Повторное использование настроек цвета

    Как вы уже знаете, гибкий шаблон Control’а можно настраивать через свойства Control’а, значение которых можно задавать в стиле. Однако Silverlight приложения редко изменяют свойства только одного Control’а за раз. Как правило, для изменения вида приложения изменяются настройки сразу у множества шаблонов. В таких ситуациях нужно уметь синхронно использовать определенные свойства Control’ов (например, настройки цвета). Для этого все "вшитые" значения вынесите из стилей и шаблонов, описав их как отдельные ресурсы. Например:

    <SolidColorBrush x:Key="BackgroundBrush" Color="Red"/>

    Затем вы можете обращаться к этим ресурсам из стилей и шаблонов:

    <Style x:Key="ButtonStyle" TargetType="Button">
        <Setter Property="Foreground" Value="White"/>
        <Setter Property="Background" Value="{StaticResource BackgroundBrush}"/>
        <Setter Property="Template" Value="{StaticResource ButtonTemplate}"/>
    </Style>

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

    Для большей гибкости вы можете вынести в отдельный ресурс даже настройки цветов, а затем использовать их как ресурсы кисти:

    <Color
       x:Key="BackgroundColor">#FF800000</Color>
    <SolidColorBrush
       x:Key="BackgroundBrush" Color="{StaticResource BackgroundColor}"/>

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

    Замечание: при объявлении цвета как отдельного ресурса ему может быть задан цвет в виде имени цвета или в виде шестнадцатеричного HTML-кода цвета (как в примере). Но, к сожалению, нельзя объявить цвет в XAML, используя набор красного, зеленого, и синего составляющих цвета.

    Ключевые термины

    Styles: совокупность значений свойств, которые можно все сразу применить к нужному элементу.

    Templates: каждый Control содержит встроенный набор правил, определяющий его отрисовку (в виде набора более простых элементов). Этот набор правил называется шаблоном Control’а (control template). Описывается он как блок XAML-разметки и применяется к Control’у через свойство "Template".

    Краткие итоги

    В этой лекции мы рассмотрели механизм применения некоторого набора свойств к одному или нескольким элементам управления - стили. С помощью стилей можно создавать однородные темы и применять их к разным приложениям. Однако у стилей имеются ограничения на изменение свойств, описанных в классе элемента. В Silverlight имеется куда более радикальный инструмент для настройки подобных вещей, называемый шаблонами (templates). Тогда как стили можно применять к любому Silverlight элементу, использование шаблонов ограничено Silverlight Control’ами, т.е. элементами, которые наследуются от класса Control, принадлежащего пространству имен System.Windows.Controls. Более детально эти отличия мы рассмотрим в следующей лекции.

    Набор для практики

    Вопросы:

  • Приведите пример необходимости использования класса ContentPresenter.
  • Назначение ресурсов в WPF. Пример использования?
  • Назначение стилей в WPF. Пример использования?
  • Назначение шаблонов в WPF. Пример использования?
  • Поясните назначение установки шаблонов через стили.
  • Вернуться к учебному плану