WPF
styles
multiple styles
UI design
C#

How to apply multiple styles in WPF

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

WPF does not support applying multiple styles to a single element directly — a FrameworkElement has one Style property, not a list. However, there are several patterns to combine styles: the BasedOn property for style inheritance, merged ResourceDictionary for organizing styles, a custom StyleMerger markup extension, and attaching additional setters via attached behaviors. The most common and recommended approach is BasedOn, which creates a chain of inherited styles.

Style Inheritance with BasedOn

BasedOn lets one style inherit all setters from a parent style and add or override properties:

xml
1<Window.Resources>
2    <!-- Base style for all buttons -->
3    <Style x:Key="BaseButtonStyle" TargetType="Button">
4        <Setter Property="FontSize" Value="14"/>
5        <Setter Property="Padding" Value="10,5"/>
6        <Setter Property="Margin" Value="5"/>
7    </Style>
8
9    <!-- Primary button extends base -->
10    <Style x:Key="PrimaryButtonStyle" TargetType="Button"
11           BasedOn="{StaticResource BaseButtonStyle}">
12        <Setter Property="Background" Value="#007ACC"/>
13        <Setter Property="Foreground" Value="White"/>
14    </Style>
15
16    <!-- Danger button extends base with different colors -->
17    <Style x:Key="DangerButtonStyle" TargetType="Button"
18           BasedOn="{StaticResource BaseButtonStyle}">
19        <Setter Property="Background" Value="#D32F2F"/>
20        <Setter Property="Foreground" Value="White"/>
21    </Style>
22</Window.Resources>
23
24<StackPanel>
25    <Button Style="{StaticResource PrimaryButtonStyle}" Content="Save"/>
26    <Button Style="{StaticResource DangerButtonStyle}" Content="Delete"/>
27</StackPanel>

PrimaryButtonStyle inherits FontSize, Padding, and Margin from BaseButtonStyle and adds its own Background and Foreground.

Multi-Level Style Chain

You can chain multiple levels of BasedOn:

xml
1<Window.Resources>
2    <!-- Level 1: Typography -->
3    <Style x:Key="TypographyStyle" TargetType="Control">
4        <Setter Property="FontFamily" Value="Segoe UI"/>
5        <Setter Property="FontSize" Value="14"/>
6    </Style>
7
8    <!-- Level 2: Spacing (inherits typography) -->
9    <Style x:Key="SpacedControlStyle" TargetType="Control"
10           BasedOn="{StaticResource TypographyStyle}">
11        <Setter Property="Margin" Value="5"/>
12        <Setter Property="Padding" Value="8,4"/>
13    </Style>
14
15    <!-- Level 3: Themed button (inherits typography + spacing) -->
16    <Style x:Key="ThemedButtonStyle" TargetType="Button"
17           BasedOn="{StaticResource SpacedControlStyle}">
18        <Setter Property="Background" Value="#2196F3"/>
19        <Setter Property="Foreground" Value="White"/>
20        <Setter Property="BorderThickness" Value="0"/>
21    </Style>
22</Window.Resources>
23
24<Button Style="{StaticResource ThemedButtonStyle}" Content="Click Me"/>
25<!-- Gets FontFamily, FontSize, Margin, Padding, Background, Foreground, BorderThickness -->

Implicit Styles with BasedOn

Implicit styles (no x:Key) apply to all controls of a given type. You can combine implicit and explicit styles:

xml
1<Window.Resources>
2    <!-- Implicit style applies to ALL TextBoxes -->
3    <Style TargetType="TextBox">
4        <Setter Property="FontSize" Value="14"/>
5        <Setter Property="Margin" Value="5"/>
6        <Setter Property="Padding" Value="4"/>
7    </Style>
8
9    <!-- Named style for search boxes, inherits from implicit -->
10    <Style x:Key="SearchBoxStyle" TargetType="TextBox"
11           BasedOn="{StaticResource {x:Type TextBox}}">
12        <Setter Property="Background" Value="#F5F5F5"/>
13        <Setter Property="BorderBrush" Value="#CCCCCC"/>
14    </Style>
15</Window.Resources>
16
17<TextBox Text="Regular textbox"/>  <!-- Gets implicit style -->
18<TextBox Style="{StaticResource SearchBoxStyle}" Text="Search..."/>  <!-- Gets both -->

The BasedOn="{StaticResource {x:Type TextBox}}" syntax references the implicit style for TextBox.

Custom Markup Extension for Merging Styles

For cases where BasedOn chains are not flexible enough, you can create a markup extension that merges multiple styles at runtime:

csharp
1using System.Windows;
2using System.Windows.Markup;
3
4[MarkupExtensionReturnType(typeof(Style))]
5public class MergedStyleExtension : MarkupExtension
6{
7    public string StyleKeys { get; set; }
8
9    public override object ProvideValue(IServiceProvider serviceProvider)
10    {
11        var merged = new Style();
12        var keys = StyleKeys.Split(',');
13
14        var provideValueTarget = serviceProvider
15            .GetService(typeof(IProvideValueTarget)) as IProvideValueTarget;
16        var element = provideValueTarget?.TargetObject as FrameworkElement;
17
18        foreach (var key in keys)
19        {
20            var trimmedKey = key.Trim();
21            if (element?.TryFindResource(trimmedKey) is Style style)
22            {
23                foreach (Setter setter in style.Setters)
24                {
25                    merged.Setters.Add(setter);
26                }
27                foreach (var trigger in style.Triggers)
28                {
29                    merged.Triggers.Add(trigger);
30                }
31            }
32        }
33
34        return merged;
35    }
36}
xml
<!-- Usage -->
<Button Style="{local:MergedStyle StyleKeys='TypographyStyle, SpacingStyle, ColorStyle'}"
        Content="Merged"/>

This approach is a workaround — use it only when BasedOn chains cannot express the desired combination.

Attached Behavior Pattern

Another approach uses attached properties to add supplementary styling:

csharp
1public static class StyleBehavior
2{
3    public static readonly DependencyProperty ExtraStyleProperty =
4        DependencyProperty.RegisterAttached(
5            "ExtraStyle", typeof(Style), typeof(StyleBehavior),
6            new PropertyMetadata(null, OnExtraStyleChanged));
7
8    public static Style GetExtraStyle(DependencyObject obj)
9        => (Style)obj.GetValue(ExtraStyleProperty);
10
11    public static void SetExtraStyle(DependencyObject obj, Style value)
12        => obj.SetValue(ExtraStyleProperty, value);
13
14    private static void OnExtraStyleChanged(
15        DependencyObject d, DependencyPropertyChangedEventArgs e)
16    {
17        if (d is FrameworkElement element && e.NewValue is Style extraStyle)
18        {
19            var baseStyle = element.Style ?? new Style(element.GetType());
20            var merged = new Style(element.GetType());
21
22            foreach (Setter setter in baseStyle.Setters) merged.Setters.Add(setter);
23            foreach (Setter setter in extraStyle.Setters) merged.Setters.Add(setter);
24
25            element.Style = merged;
26        }
27    }
28}
xml
<Button Style="{StaticResource BaseButtonStyle}"
        local:StyleBehavior.ExtraStyle="{StaticResource HighlightStyle}"
        Content="Combined"/>

Common Pitfalls

  • Trying to set the Style property twice on one element: XAML does not support setting the same property twice. <Button Style="{StaticResource A}" Style="{StaticResource B}"/> causes a compile error. Use BasedOn or a markup extension instead.
  • Circular BasedOn references: Style A based on Style B based on Style A creates an infinite loop that crashes at runtime with a StackOverflowException. Always structure style inheritance as a directed acyclic chain.
  • BasedOn with mismatched TargetType: A Button style can be based on a Control or ButtonBase style (ancestor types), but not on a TextBox style. The base style's TargetType must be the same type or an ancestor of the derived style's TargetType.
  • Overriding setters unintentionally: When a derived style sets the same property as the base style, the derived value wins. This is usually desired, but forgetting that a base style sets a property can lead to confusion when your explicit setter seems to be ignored.
  • Performance with dynamic style merging: Custom markup extensions that merge styles at runtime create new Style objects for each element. In data-bound lists with thousands of items, this can cause measurable allocation overhead. Prefer static BasedOn chains for performance-critical scenarios.

Summary

  • WPF elements can only have one Style — use BasedOn to inherit and extend styles in a chain
  • Create a base style with shared properties, then derive specialized styles from it
  • Reference implicit styles in BasedOn with {StaticResource {x:Type TargetType}}
  • For advanced scenarios, use a custom MarkupExtension or attached behaviors to merge multiple styles at runtime
  • Always prefer BasedOn chains over runtime merging — they are simpler, faster, and easier to maintain
  • Avoid circular BasedOn references and ensure TargetType compatibility in the chain

Related reading
Course
Intermediate
27 lessons
14 hours
OOD Fundamentals

Master object-oriented design from first principles, SOLID, design patterns, and classic interview problems with hands-on coding.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.