A resource is an object defined once in markup and used by name from other places: a brush, a style, a template, a string, a converter. Resources are kept in resource dictionaries, which every framework element has as its Resources property and which can also be files of their own. Styles and templates are resources with structure of their own.
Dictionaries and keys
<Window.Resources>
<SolidColorBrush x:Key="Accent" Color="#FF2D6CDF"/>
<Style TargetType="Button"> <!-- the key is {x:Type Button} -->
<Setter Property="Background" Value="{StaticResource Accent}"/>
</Style>
<DataTemplate DataType="{x:Type local:Person}"> <!-- the key is {x:Type local:Person} -->
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</Window.Resources>
- Where. The
Resourcesproperty of anyFrameworkElement(Window.Resources,Grid.Resources,Button.Resources), ofApplication(Application.Resources), ofStyleand of templates in some frameworks, or a file whose root isResourceDictionary. Its children are the items; the explicit<ResourceDictionary>element is optional and is needed only to merge other dictionaries. - Keys. Every item has a key:
x:Key="name", or an implied one. AStylewith aTargetTypeand no key has the type as its key, so it applies to every element of that type below the dictionary (an implicit style); aDataTemplatewith aDataTypeand no key is chosen automatically for objects of that type.ControlTemplatehas no implied key. UWP, WinUI and Silverlight accept anx:Nameas a key. In Avalonia,ControlThemeis keyed byx:Keyor itsTargetType. - Uniqueness. A key occurs once in a dictionary (implied keys included); a second one is an error when the dictionary is loaded. The same key may occur in different dictionaries, and the nearest one wins.
- Sharing. an item is made once and shared by every use, unless
x:Shared="false". AFreezable(a brush) is frozen when it can be, which makes it cheap to share. - Types. any object: brushes, colours, geometry, styles, templates, storyboards, converters, data providers, numbers and strings (
<sys:Double x:Key="Pad">12</sys:Double>or<x:Double>in XAML 2009).
Lookup
A reference by {StaticResource Key} or {DynamicResource Key} looks in the element’s own dictionary, then in each ancestor’s, up to the root of the page, then in the application’s dictionary (Application.Resources), then in the theme dictionaries, then in the system resources (SystemColors, SystemFonts, SystemParameters). For an element made by a template, the template’s own dictionary and the templated parent come first. A StaticResource is resolved once, while the markup is read, so the item must come before the reference in the file when they are in the same dictionary; a DynamicResource is resolved at run time and again whenever the resource changes, and can refer forward. Only a dependency property can take a DynamicResource. UWP and WinUI add {ThemeResource}, which is looked up through the theme dictionaries (ResourceDictionary.ThemeDictionaries, keys Light, Dark, HighContrast) and again when the theme changes.
Merged dictionaries and addresses
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Styles/Buttons.xaml"/>
<ResourceDictionary Source="pack://application:,,,/Theme;component/Colors.xaml"/>
</ResourceDictionary.MergedDictionaries>
<SolidColorBrush x:Key="Local" Color="Red"/>
</ResourceDictionary>
</Application.Resources>
MergedDictionaries holds other dictionaries whose items are searched after the dictionary’s own items, in reverse order of listing (the last merged is searched first). Each merged dictionary is a separate dictionary, so keys may repeat between them. Source is a relative address (relative to the file that contains it), a pack://application:,,,/Assembly;component/path address (WPF), an ms-appx:///path address (UWP and WinUI), or an avares://Assembly/path address (Avalonia). Avalonia lists them in MergedDictionaries too, and adds Styles with StyleInclude Source="...". WPF’s theme dictionaries are found by ThemeInfoAttribute and the Themes/ file names listed on the file structure page.
Styles
A Style is a bundle of property values (and behaviour) applied to elements of one type.
| Part | Meaning |
|---|---|
TargetType | the type the style applies to (Button, {x:Type local:A}); required except when every setter names its type |
BasedOn | a style this one extends: BasedOn="{StaticResource Base}"; the setters of both apply, this one wins |
Setters (content) | <Setter Property="Margin" Value="4"/>: a property and a value; the value may be a property element; TargetName inside a template trigger names the template element; EventSetter connects an event handler |
Triggers | conditions that apply setters while true, see below |
Resources | a dictionary local to the style (and its own name scope) |
Avalonia: Selector | a CSS-like selector instead of TargetType: <Style Selector="Button.accent:pointerover">; Style.Animations and nested Styles (Selector="^:pressed") |
| UWP and WinUI | Style has TargetType, BasedOn and Setters; no Triggers: the same effect is made with visual states |
Triggers (WPF)
| Element | Condition |
|---|---|
Trigger | a dependency property has a value: Property, Value, SourceName; contains Setters, EnterActions, ExitActions |
MultiTrigger | several Conditions (Property, Value) are all true |
DataTrigger | a binding has a value: Binding, Value |
MultiDataTrigger | several Conditions with a Binding and a Value are all true |
EventTrigger | a routed event is raised: RoutedEvent, SourceName; contains actions such as BeginStoryboard (not setters) |
Trigger actions are BeginStoryboard, PauseStoryboard, ResumeStoryboard, StopStoryboard, SeekStoryboard, SkipStoryboardToFill, RemoveStoryboard, SetStoryboardSpeedRatio and ControllableStoryboardAction; see animation. Avalonia has no triggers; its selectors and pseudo-classes (:pointerover, :pressed, :focus, :disabled, :checked) do the same. UWP and WinUI have StateTrigger, AdaptiveTrigger (MinWindowWidth, MinWindowHeight) and CompositeTrigger inside visual states; MAUI has Trigger, DataTrigger, MultiTrigger, EventTrigger and AdaptiveTrigger in Style.Triggers or Element.Triggers, and VisualStateManager.
Templates
| Template | What it defines | Main members |
|---|---|---|
ControlTemplate | the visual tree of a control (its look, not its behaviour) | TargetType, content (the root element), Triggers (WPF); parts named PART_… that the control looks for; ContentPresenter and ItemsPresenter mark where content goes; {TemplateBinding} reads the control’s properties |
DataTemplate | the visual tree for a data object | DataType, Triggers; used by ContentTemplate, ItemTemplate, HeaderTemplate or automatically by DataType |
HierarchicalDataTemplate (WPF), TreeDataTemplate (Avalonia) | a data template with a child collection for trees and menus | ItemsSource, ItemTemplate, ItemContainerStyle |
ItemsPanelTemplate | the panel an items control lays its items out in | one panel element |
DataTemplateSelector (a class, not markup) | chooses a template by code | referenced as ItemTemplateSelector="{StaticResource Picker}" |
ControlTemplate in MAUI | the visual tree of a TemplatedView or ContentPage; ContentPresenter marks the content; DataTemplate for ListView/CollectionView items | {TemplateBinding}, {Binding} |
The type of a framework template is the family FrameworkTemplate; the viewer treats any element whose name ends in Template as a template.
Visual states
VisualStateManager.VisualStateGroups (an attached property) holds VisualStateGroups, each with VisualStates that contain a Storyboard or Setters (UWP, WinUI, MAUI: VisualState.Setters) and optional VisualTransitions (WPF, Silverlight). The groups of a control are named in its documentation (CommonStates with Normal, MouseOver, Pressed, Disabled; FocusStates; ValidationStates) and a control looks for the parts and states its template defines. It is the main way to change a look in UWP, WinUI, Silverlight and MAUI, where there are no property triggers.
Name scopes
A name scope is the region in which an x:Name is unique and found by name. The root of the document is a scope; so is each template (ControlTemplate, DataTemplate and the others), because a template is applied many times and each application has its own names; so is a Style in WPF, where it lets triggers and storyboards name elements. A name may therefore repeat in different templates but not in one scope; the viewer’s Names tab shows each name with its scope. FindName, Storyboard.TargetName and ElementName bindings look names up in the scope. Dictionary items are not a scope of their own: the name of an element declared in Window.Resources is in the window’s scope.
Not described
Known, not yet covered
- Reference: the property lists of the Avalonia style system (selectors, classes,
Transitions,Animations) and the MAUI trigger types are summarised, not complete. - Reference: the part and state names of each WPF control’s template are not listed.
Unknown
- Reference: the lookup order was written from the documentation of WPF; the order in the other frameworks was not verified.