Resources, styles, templates and themes
Resource lookup order, implicit and explicit styles, control and data templates, triggers, and merged theme dictionaries that keep a design consistent.
Resource lookup order
<Window.Resources>
<SolidColorBrush x:Key="Accent">#2F6FED</SolidColorBrush>
<sys:Double x:Key="Gap" xmlns:sys="clr-namespace:System;assembly=System.Runtime">12</sys:Double>
</Window.Resources>
<StackPanel>
<TextBlock Text="Total" Foreground="{StaticResource Accent}" />
<Border Background="{DynamicResource PanelBackground}" />
</StackPanel>- The element's own
Resources. - Each ancestor's
Resources, walking up the logical tree. Application.Current.Resources.- The system and theme dictionaries built into WPF.
- The default value on the property itself.
| Reference | Resolved | Cost | Use when |
|---|---|---|---|
StaticResource | At load time, once | Cheapest | The resource never changes after load |
DynamicResource | On every access | A lookup per request | The resource may be swapped at runtime, e.g. a theme |
x:Static | A compile-time constant | Free | A fixed number or string, not a brush |
Styles and triggers
<Style x:Key="PrimaryButton" TargetType="Button">
<Setter Property="Padding" Value="16,8" />
<Setter Property="FontWeight" Value="SemiBold" />
<Setter Property="Background" Value="{StaticResource Accent}" />
<Setter Property="Foreground" Value="White" />
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Opacity" Value="0.9" />
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Opacity" Value="0.5" />
</Trigger>
<DataTrigger Binding="{Binding IsBusy}" Value="True">
<Setter Property="IsEnabled" Value="False" />
</DataTrigger>
</Style.Triggers>
</Style>- Omit
x:Keyand the style becomes implicit: it applies to every control of that type in the resource's scope. - A style can only set properties; a template defines structure. Setting
Templateinside a style is the normal way to restyle a control completely. - Triggers in a style are evaluated in order and the last matching setter wins for a given property - order matters when several can fire.
- Use
BasedOnto extend an existing style instead of copying every setter.
ControlTemplate and DataTemplate
<!-- control template: replaces the structure of the button itself -->
<ControlTemplate x:Key="RoundButton" TargetType="Button">
<Border x:Name="Chrome"
CornerRadius="6"
Background="{TemplateBinding Background}"
Padding="{TemplateBinding Padding}">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="Chrome" Property="Background" Value="#1F5ED0" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<!-- data template: how one item of a collection is rendered -->
<DataTemplate x:Key="OrderRow" DataType="{x:Type models:Order}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Id}" Width="80" />
<TextBlock Text="{Binding Customer}" />
</StackPanel>
</DataTemplate><!-- theme dictionaries loaded at startup -->
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/Themes/Colors.Light.xaml" />
<ResourceDictionary Source="pack://application:,,,/Themes/Controls.xaml" />
</ResourceDictionary.MergedDictionaries>Keep raw values - colours, sizes, corner radii - in one dictionary, and reference them from styles and templates. A theme swap is then a single dictionary replacement, which is only possible if nothing downstream hard-codes a colour.
💡
Use
TemplateBinding inside a ControlTemplate when the value comes from the templated control's own properties. Use {Binding RelativeSource={RelativeSource TemplatedParent}, Path=...} when you need a converter or a two-way mode - TemplateBinding supports neither.FAQ
Why is my DynamicResource not updating?
A dictionary swap replaces the object, but a bound value only re-reads on the next lookup. Reassign the merged dictionary in the intended order and make sure the property was set with
DynamicResource, not StaticResource.Where should implicit styles live?
Not in
App.xaml unless you truly mean application-wide. An implicit style in a module's resource dictionary keeps the redesign local instead of leaking into every window.Related
Custom controls and user controls Items controls, collections and virtualization
Last refreshed 2026-09-18.