Стилизация и использование шаблонов
Обновлен: Ноябрь 2007
Стилизация и использование шаблонов Windows Presentation Foundation (WPF) относятся к набору возможностей (стили, шаблоны, триггеры и раскадровки), который позволяют разработчикам приложения, документа или пользовательский интерфейс создавать реалистичные визуальные эффекты и проводить стандартизацию согласованного внешнего вида своих продуктов. Несмотря на то, что автор или разработчик может настроить внешний вид отдельно для каждого приложения, строгая модель стилизации и шаблонов необходима для поддержки и общего использования внешнего вида внутри приложений и между ними. Windows Presentation Foundation (WPF) предоставляет такую модель.
Другой возможностью модели стилизации WPF является разделение представления и логики. Это означает, что дизайнеры могут создавать внешний вид приложения только с помощью XAML, а разработчики одновременно могут работать над логикой программы, используя C# или Visual Basic.
В этом обзоре обсуждается приложение Пример знакомства со стилизацией и использованием шаблонов, которое имеет два элемента TextBlock и элемент управления ListBox, который связан со списком изображений:
Этот обзор уделяет внимание аспектам стилизации и использованию шаблонов приложения и не затрагивает вопросы, связанные с привязкой данных. Сведения о привязке данных см. в разделе Общие сведения о связывании данных.
Кроме того, важно понимать ресурсы, которые позволяют повторно использовать стили и шаблоны. Дополнительные сведения о ресурсах содержатся в разделе Общие сведения о ресурсах.
В этом разделе содержатся следующие подразделы.
- Основы стиля
- Шаблоны данных
- Шаблоны элементов управления
- Триггеры
- Совместно используемые ресурсы и темы
- Связанные разделы
Основы стиля
Style — это удобный способ для применения набора значений свойств к нескольким элементам. Например, рассмотрим следующие элементы TextBlock и их внешний вид по умолчанию:
<TextBlock>My Pictures</TextBlock>
<TextBlock>Check out my new pictures!</TextBlock>
Внешний вид по умолчанию можно изменить путем задания свойств, например FontSize и FontFamily непосредственно для каждого элемента TextBlock. Однако, если элементы TextBlock должны совместно использовать некоторые свойства, можно создать Style в разделе Resources файла XAML, как показано ниже:
<Window.Resources>
...
<!--A Style that affects all TextBlocks-->
<Style TargetType="TextBlock">
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="FontFamily" Value="Comic Sans MS"/>
<Setter Property="FontSize" Value="14"/>
</Style>
...
</Window.Resources>
При установке TargetType стиля в тип TextBlock, стиль будет применен ко всем элементам TextBlock в окне.
Теперь элементы TextBlock выглядят следующим образом:
Этот подраздел состоит из следующих пунктов.
- Расширяемые стили
- Отношение свойства TargetType и атрибута x:Key
- Стили и ресурсы
- Установка стилей программным путем
- Привязки, динамические ресурсы и обработчики событий
Расширяемые стили
Предположим, что два элемента TextBlock должны совместно использовать некоторые свойства, например FontFamily и центрированное HorizontalAlignment, но текст "My Pictures" также должен иметь дополнительные свойства. Это можно сделать путем создания нового стиля на основе первого стиля, как показано ниже:
<Window.Resources>
...
<!--A Style that extends the previous TextBlock Style-->
<!--This is a "named style" with an x:Key of TitleText-->
<Style BasedOn="{StaticResource {x:Type TextBlock}}"
TargetType="TextBlock"
x:Key="TitleText">
<Setter Property="FontSize" Value="26"/>
<Setter Property="Foreground">
<Setter.Value>
<LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
<LinearGradientBrush.GradientStops>
<GradientStop Offset="0.0" Color="#90DDDD" />
<GradientStop Offset="1.0" Color="#5BFFFF" />
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Setter.Value>
</Setter>
</Style>
...
</Window.Resources>
Обратите внимание, что указанному выше стилю присваивается x:Key. Чтобы применить стиль, можно установить свойство StyleTextBlock в значение x:Key, как показано ниже:
<TextBlock Style="{StaticResource TitleText}" Name="textblock1">My Pictures</TextBlock>
<TextBlock>Check out my new pictures!</TextBlock>
Этот стиль TextBlock теперь имеет значение HorizontalAlignment, равное Center, значение FontFamily, равное Comic Sans MS, значение FontSize, равное 26, и значение Foreground, устанавливаемое в LinearGradientBrush, как показано в примере. Обратите внимание, что значение FontSize базового стиля переопределено. Если имеется несколько параметров Setter того же свойства в Style, то объявленный последним Setter получает более высокий приоритет.
Ниже показано, как теперь выглядят элементы TextBlock:
Этот стиль TitleText расширяет стиль, созданный для типа TextBlock. Можно также расширить стиль, имеющий x:Key, используя значение x:Key. В качестве примера см. пример, приведенный для свойства BasedOn.
Отношение свойства TargetType и атрибута x:Key
Как показано в первом примере, установка свойства TargetType в TextBlock без присвоения стиля x:Key, применит стиль ко всем элементам TextBlock. В этом случае для x:Key неявным образом устанавливается значение {x:Type TextBlock}. Это означает, что при явном задании значения x:Key, отличного от {x:Type TextBlock}, Style не применится ко всем элементам TextBlock автоматически. Вместо этого следует явно применить стиль (с помощью значения x:Key) к элементам TextBlock. Если стиль находится в разделе ресурсов, а свойство TargetType в стиле не задается, то необходимо указать x:Key.
Помимо значения по умолчанию для x:Key, свойство TargetType указывает тип, к которому применяются свойства установщика. Если TargetType не указывается, необходимо уточнить свойства в объектах Setter с именем класса при помощи синтаксиса Property="ClassName.Property". Например, вместо установки Property="FontSize" необходимо установить Property в "TextBlock.FontSize" или "Control.FontSize".
Также обратите внимание, что большое число элементов управления WPF состоит из комбинации других элементов управления WPF. При создании стиля, применяющегося ко всем элементам управления этого типа, можно получить непредвиденные результаты. Например, если создается стиль, предназначенный для типа TextBlock в Window, стиль будет применен ко всем элементам управления TextBlock в окне даже в том случае, если TextBlock является частью другого элемента управления, например ListBox.
Стили и ресурсы
Стиль может использоваться для любого элемента, производного от FrameworkElement или FrameworkContentElement. Наиболее распространенный способ для объявления стилей — это их объявление в качестве ресурса в разделе Resources файла XAML, как показано в предыдущих примерах. Так как стили являются ресурсами, они подчиняются тем же правилам обзора данных, которые применяются ко всем ресурсам; место объявления стиля влияет на место его применения. Если, например, объявить стиль в корневом элементе файла XAML определения приложения, этот стиль можно будет использовать в любом месте приложения. Если создается приложение переходов, а стиль объявляется в одном из файлов приложения XAML, стиль может использоваться только в этом XAML файле. Дополнительные сведения о правилах видимости ресурсов см. в разделе Общие сведения о ресурсах.
Кроме того, дополнительные сведения о стилях и ресурсах можно найти в разделе Совместно используемые ресурсы и темы этого обзора.
Установка стилей программным путем
Для присвоения именованного стиля к элементу программными средствами получите стиль из коллекции ресурсов и присвойте его свойству элемента Style. Обратите внимание, что элементы в коллекции ресурсов имеют тип Object, поэтому необходимо привести полученный стиль к Style перед присвоением его свойству Style. Например, чтобы задать определенный стиль TitleText на TextBlock с именем textblock1, выполните следующие действия.
textblock1.Style = (Style)(this.Resources["TitleText"]);
Обратите внимание, что после того, как стиль применен, он запечатывается и не может быть изменен. Чтобы динамически изменить стиль, который уже применен, необходимо создать новый стиль для замены существующего. Дополнительные сведения см. в свойстве IsSealed.
Можно создать объект, который выбирает стиль для применения на основе пользовательской логики. См. пример, приведенный для класса StyleSelector.
Привязки, динамические ресурсы и обработчики событий
Обратите внимание,что свойство Setter.Value можно использовать для указания Привязка расширения разметки или Расширение разметки DynamicResource. Для получения дополнительных сведений см. примеры, приведенные для свойства Setter.Value.
На данный момент мы рассмотрели использование установщиков для установки значения свойства. Обработчики событий можно также указать в стиле. Дополнительные сведения см. в разделе EventSetter.
Шаблоны данных
В этом приложении примера присутствует элемент управления ListBox, который связан со списком фотографий:
<ListBox ItemsSource="{Binding Source={StaticResource MyPhotos}}"
Background="Silver" Width="600" Margin="10" SelectedIndex="0"/>
В настоящее время этот ListBox выглядит так:
Большинство элементов управления имеют некоторый тип содержимого, и это содержимое часто извлекается из связанных данных. В этом примере данные представляют собой список фотографий. В WPF для определения визуального представления данных используется DataTemplate. То, что будет помещено в DataTemplate, определяет внешний вид данных в отображаемом приложении.
В приложении образца каждый пользовательский объект Photo имеет свойство Source типа строки, которая указывает путь к файлу изображения. В настоящее время объекты фотографий отображаются как пути к файлам.
Чтобы отобразить фотографии как изображения, создается DataTemplate в качестве ресурса:
<Window.Resources>
...
<!--DataTemplate to display Photos as images
instead of text strings of Paths-->
<DataTemplate DataType="{x:Type local:Photo}">
<Border Margin="3">
<Image Source="{Binding Source}"/>
</Border>
</DataTemplate>
...
</Window.Resources>
Обратите внимание, что свойство DataType очень похоже на свойство TargetType из Style. Если DataTemplate расположен в разделе ресурсов, то при указании свойства DataType для типа и отсутствии присвоения ему x:KeyDataTemplate будет применяться при каждом отображении этого типа. Пользователь всегда может присвоить DataTemplatex:Key и затем задать его как StaticResource для свойств, которые принимают типы DataTemplate, такие как свойство ItemTemplate или свойство ContentTemplate.
DataTemplate в приведенном выше примере определяет то, что существовующий объект Photo должен отображаться как Image внутри Border. С этим DataTemplate приложение теперь выглядит следующим образом:
Модель шаблонов данных предоставляет другие возможности. Например, если данные коллекции, которая содержит другие коллекции, отображаются с помощью типа HeaderedItemsControl (например Menu или TreeView), то существует HierarchicalDataTemplate. Другой возможностью шаблонов данных является DataTemplateSelector, который позволяет выбрать DataTemplate для использования на основе пользовательской логики. Дополнительные сведения содержатся в разделе Общие сведения о шаблонах данных, который предоставляет более подробное рассмотрение различных функций шаблонов данных.
Шаблоны элементов управления
Этот подраздел состоит из следующих пунктов.
- Без использования ControlTemplate
- Что такое ControlTemplate?
- Создание ControlTemplate
- Свойство IsItemsHost
- ItemsPresenter и ContentPresenter
- TemplateBinding
Теперь, когда фотографии отображаются в виде изображений, изменим отображение по вертикали на отображение по горизонтали, чтобы сделать ListBox горизонтальным.
Без использования ControlTemplate
Во-первых, важно подчеркнуть, что необязательно использовать ControlTemplate для создания горизонтального ListBox. ListBox имеет свойство ItemsPanel, которое позволяет задать ItemsPanelTemplate — шаблон, который управляет макетом элементов ListBox. Разработчик может просто создать стиль ListBox и установить свойство ItemsPanel, как в следующем примере:
<Style TargetType="ListBox">
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"
VerticalAlignment="Center"
HorizontalAlignment="Center"/>
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
</Style>
Это дает желаемый результат, отображая горизонтальный ListBox. В этом примере показано, что в зависимости сценария можно использовать другие варианты, отличные от замены ControlTemplate. Например, если необходим горизонтальный ListBox с дополнительными свойствами, например с закругленными углами, то нужно использовать ControlTemplate элемента управления ListBox.
Перед тем, как привести пример этой операции, необходимо объяснить технологию ControlTemplate.
Что такое ControlTemplate?
Большинство элементов управления имеет внешний вид и поведение. Рассмотрим кнопку: ее внешним видом является область для нажатия, а ее поведением является событие Click, которое вызывается в ответ на нажатие кнопки.
Иногда элемент управления предоставляет нужное поведение, но не обладает требуемым внешним видом. В предыдущих примерах мы продемонстрировали использование установщиков стиля для установки значений свойств и изменения внешнего вида элемента управления. Однако, чтобы изменить структуру элемента управления или задать значения свойств компонентов, составляющих элемент управления, необходимо использовать ControlTemplate.
В WPF, ControlTemplate элемента управления определяет его внешний вид. Структуру и внешний вид элемента управления можно изменить, определив новый ControlTemplate для элемента управления. В большинстве случаев это обеспечивает достаточную гибкость и освобождает от необходимости написания собственных пользовательских элементов управления. Если собственный ControlTemplate для элемента управления не будет определен, то система будет использовать шаблон по умолчанию, соответствующий системной теме — той теме, которая дает элементу управления Button его внешний вид по умолчанию.
Следует иметь в виду, что создание ControlTemplate для элемента управления заменяет весь ControlTemplate. Например, собственный ButtonControlTemplate можно определить следующим образом.
Обратите внимание на то, что элемент ContentPresenter просто помечает требуемое место Content из Button. Различные части будут рассмотрены ниже.
<Style TargetType="Button">
<!--Set to true to not get any properties from the themes.-->
<Setter Property="OverridesDefaultStyle" Value="True"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid>
<Ellipse Fill="{TemplateBinding Background}"/>
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
После применения описанного Button отображается как Ellipse:
Следует помнить, что внешний вид Button в фокусе или нажатом состоянии является частью заменяемого внешнего вида кнопки по умолчанию. Таким образом, в зависимости от требований к элементу необходимо поместить в свое определение внешний вид кнопки при нажатии. Полный пример содержится в разделе Пример шаблона ControlTemplate для кнопки.
При создании ControlTemplate для начала необходимо использовать Примеры ControlTemplate. Чтобы ознакомиться с частями, из которых состоит элемент, обратитесь к файлу тем, расположенному в Темы, или используйте функциональные возможности Show Visual Tree XAMLPad — приложения, которое устанавливается с Пакет средств разработки программного обеспечения (SDK) для Windows.
Создание ControlTemplate
Продолжим рассмотрение примера и создадим ControlTemplate, который указывает, что ListBox является горизонтальным и имеет закругленные углы. Для замены ControlTemplate элемента управления установите свойствоTemplate в новый ControlTemplate.
<Style TargetType="ListBox">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBox">
<Border CornerRadius="5" Background="{TemplateBinding ListBox.Background}">
<ScrollViewer HorizontalScrollBarVisibility="Auto">
<StackPanel Orientation="Horizontal"
VerticalAlignment="Center"
HorizontalAlignment="Center"
IsItemsHost="True"/>
</ScrollViewer>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Таким образом, установка свойства Template ничем не отличается от установки других свойств элементов управления с помощью Style: для установки свойства Style используется Template. Это означает, что другой способ установить ControlTemplate будет состоять в непосредственном задании свойства Template для элемента управления. В этом случае необходимо создать ControlTemplate в разделе Resources, предоставить ему x:Key и затем использовать его в качестве статического ресурса. В качестве примера см. свойство Template.
Как следует из приведенного выше примера, класс ControlTemplate имеет свойство TargetType, похожее на свойство TargetType класса Style. Однако обратите внимание, что в отличие от Style и DataTemplate, ControlTemplate объекты не имеют понятия неявного ключа. Другими словами, если имеется отдельный ControlTemplate со свойством TargetType, равным типу, то ControlTemplate не будет автоматически применяться к этому типу. Также обратите внимание, что свойство TargetType необходимо в ControlTemplate, если определение шаблона содержит ContentPresenter.
Попробуйте поэкспериментировать с ControlTemplate. Например, замените StackPanel на WrapPanel, установите свойство HorizontalScrollBarVisibility из ScrollViewer в Disabled, а затем установите ширину ListBox равной 300. (WrapPanel помещает элементы в следующую строку только при нехватке места на первой строке. Если свойство HorizontalScrollBarVisibility элемента ScrollViewer не задается в Disabled, то первая строка не переполнится, так как ее можно прокрутить до конца. Таким образом WrapPanel не будет переносить элементы.)
Свойство IsItemsHost
В этом примере необходимо обратить внимание на свойство IsItemsHost. Свойство IsItemsHost используется для указания места назначения сгенерированных элементов в шаблоне ItemsControl (например, для элементов управления ListBox, работающих со списком элементов). Установка свойства в значение true на StackPanel означает, что все элементы, добавленные в ListBox, переходят в StackPanel. Обратите внимание, что это свойство работает только с типами Panel.
ItemsPresenter и ContentPresenter
В то же время, обратите внимание, что при указании панели в ControlTemplate и ее пометке в качестве IsItemsHost, ItemsPanel не может быть заменено пользователем элемента управления без использования ControlTemplate. Поэтому выполняйте пометку только в том случае, если панель не будет заменяться без использования шаблона. Кроме того, для пометки места назначения элементов можно использовать элемент ItemsPresenter, а затем указать ItemsPanelTemplate путем установки свойства ItemsPanel. Страница ItemsPanelTemplate содержит пример, который демонстрирует эту операцию. Другой пример, использующий ItemsPresenter, содержится в разделе Пример шаблона элемента управления ControlTemplate элемента TreeView.
При создании шаблона для ContentControl (например, для Button) соответствующим элементом является ContentPresenter. Аналогичным образом, этот элемент необходимо поместить в ControlTemplate типа ContentControl для указания места отображения содержимого, как показано в примере раздела Что такое ControlTemplate? . Другие примеры содержатся в разделах Пример метки ControlTemplate и Пример использования шаблона ControlTemplate для элемента управления ListBoxItem.
TemplateBinding
Другой важной вещью в предыдущем примере является значение Background, которое устанавливается в {TemplateBinding ListBox.Background}. Это значение указывает на то, что Background элемента Border должен быть синхронизирован со значением Background, которое установлено в ListBox. TemplateBinding аналогичен Binding. На самом деле, TemplateBinding является более эффективным, но менее функциональным, чем Binding; использование TemplateBinding эквивалентно использованию Binding с свойством Source, установленным в RelativeSource.TemplatedParent.
TemplateBinding используется в ControlTemplate в том случае, когда необходимо предоставить пользователю элемента возможность управления значениями определенных свойств. TemplateBinding является расширением разметки, представленным классом TemplateBindingExtension.
Обратите внимание на то, что DataTemplate и ControlTemplate сходны в том, что их содержимое становится визуализацией объекта. Вместе с определением ListBox ControlTemplate приложение теперь выглядит так:
Триггеры
Style, ControlTemplate и DataTemplate имеют свойство Triggers, которое может содержать набор триггеров. Триггер задает свойства или начинает действия (например, анимацию) при изменении значения свойства или при возникновении события.
Этот подраздел состоит из следующих пунктов.
- Триггеры свойств
- EventTrigger и раскадровки
- MultiTrigger, DataTrigger и MultiDataTrigger
Триггеры свойств
Чтобы продемонстрировать использование триггеров для установки свойств, сделаем каждый ListBoxItem частично прозрачным, если он не является выбранным.
Следующий стиль устанавливает значение Opacity элемента ListBoxItem равным 0.5. Когда свойство IsSelected равно true, Opacity устанавливается в 1.0.
<Style TargetType="ListBoxItem">
<Setter Property="Opacity" Value="0.5" />
<Setter Property="MaxHeight" Value="75" />
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Opacity" Value="1.0" />
</Trigger>
...
</Style.Triggers>
</Style>
В этом примере Trigger используется для установки значения свойства. Обратите внимание, что класс Trigger также имеет свойства EnterActions и ExitActions, которые позволяют триггеру выполнять действия.
Обратите внимание, что мы также устанавливаем значение свойства MaxHeight элемента ListBoxItem равным 75. На следующем снимке экрана третий элемент является выбранным элементом:
EventTrigger и раскадровки
В предыдущем примере было показано, что Trigger задает значения свойств или запускает действия, основанные на значении свойства. Другим типом триггера является EventTrigger, запускающий набор действий в зависимости от наличия события. Например, следующие объекты EventTrigger указывают на то, что при вхождении указателя мыши в ListBoxItem свойство MaxHeight изменяется до значения 90 за период в 0.2 секунды. Когда указатель мыши перемещается из элемента, свойство возвращается к исходному значению за 1 секунду. Обратите внимание, что значение To не обязательно указывать для анимации MouseLeave. Это происходит потому, что анимация имеет возможность следить за исходным значением.
<EventTrigger RoutedEvent="Mouse.MouseEnter">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Duration="0:0:0.2"
Storyboard.TargetProperty="MaxHeight"
To="90" />
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
<EventTrigger RoutedEvent="Mouse.MouseLeave">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Duration="0:0:1"
Storyboard.TargetProperty="MaxHeight" />
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
Дополнительные сведения см. в разделе Общие сведения о Storyboard.
На следующем снимке экрана указатель мыши указывает на третий элемент:
MultiTrigger, DataTrigger и MultiDataTrigger
В дополнение к Trigger и EventTrigger существуют другие типы триггеров. MultiTrigger позволяет задавать значения свойств в зависимости от нескольких условий. DataTrigger и MultiDataTrigger используются в том случае, когда свойство условия связано с данными.
Полный образец, рассматриваемый в этом обзоре, содержится в разделе Пример знакомства со стилизацией и использованием шаблонов.
Совместно используемые ресурсы и темы
Обычное приложение WPF (Windows Presentation Foundation) может иметь несколько ресурсов пользовательского интерфейса (UI), которые применяются во всем приложении. В совокупности этот набор ресурсов может рассматриваться в качестве темы для приложения. WPF (Windows Presentation Foundation) предоставляет поддержку для упаковки ресурсов пользовательского интерфейса (UI) в качестве темы с помощью словаря ресурсов, который инкапсулируется в качестве класса ResourceDictionary.
Темы WPF (Windows Presentation Foundation) определяются с помощью механизмов стилизации и шаблонов, которые WPF (Windows Presentation Foundation) предоставляет для настройки отображения любого элемента.
Ресурсы темы WPF (Windows Presentation Foundation) хранятся в словарях внедренных ресурсов. Эти словари ресурсов должны быть внедрены в ту же подписанную сборку, что и сам код, или в параллельную пописанную сборку. В случае с PresentationFramework.dll (сборки, которая содержит элементы управления WPF (Windows Presentation Foundation)) ресурсы тем находятся в сериях параллельных сборок.
Тема становится последним местом остановки при поиске стиля элемента. Обычно поиск начинается с прохода вверх по дереву элементов в поисках соответствующего ресурса, затем переходит в коллекции ресурсов приложений, а затем выполняет запрос к системе. Это дает авторам приложения возможность переопределить стиль для любого объекта на уровне дерева или приложения до достижения темы.
Словари ресурсов можно определить в виде отдельных файлов, которые позволяют повторно использовать тему для нескольких приложений. Также можно создать изменяемые темы, определив несколько словарей ресурсов, которые обеспечивают одни и те же типы ресурсов, но с разными значениями. Переопределение этих стилей или других ресурсы на уровне приложения является рекомендуемым методом смены тем приложения.
Для совместного использования набора ресурсов (включая стили и шаблоны) всеми приложениями, можно создать XAML файл и определить ResourceDictionary. Например, посмотрите на следующий снимок экрана, показывающий часть Пример стилизации с использованием ControlTemplates:
Если взглянуть на файлы XAML в образце, можно заметить, что для всех файлов справедливо следующее:
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Shared.xaml" />
</ResourceDictionary.MergedDictionaries>
Общий доступ к shared.xaml определяет ResourceDictionary, содержащий набор стилей и ресурсов кисти, которая позволяет элементам управления в образце иметь согласованный внешний вид.
Дополнительные сведения см. в разделе Объединенные словари ресурсов.
При создании темы для пользовательского элемента управления обратитесь к подразделу "Внешняя библиотека элементов управления" в разделе Общие сведения о разработке управления.
См. также
Задачи
Поиск элемента, созданного шаблоном ControlTemplate
Практическое руководство. Поиск элементов, созданных с использованием шаблона DataTemplate
Пример приложения "Фотомагазин"
Основные понятия
URI типа "pack" в Windows Presentation Foundation