Search code examples
c#wpfwpf-stylematerial-design-in-xaml

How can I avoid overriding a window-wide style in WPF?


I'm using the MaterialDesign nuget package for my WPF application. According to the tutorial, by applying window-wide properties, every element will inherit the MaterialDesign style. However, if I apply a custom style to an element, that element loses its MaterialDesign style. I can get around this by applying inline styles, but that is very repetitive and error prone.

I think the picture shows it better:

Buttons

And here is my xaml:

<Window
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:TestApp"
        xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" x:Class="TestApp.MainWindow"
        mc:Ignorable="d"
        TextElement.Foreground="{DynamicResource MaterialDesignBody}"
        TextElement.FontWeight="Regular"
        TextElement.FontSize="13"
        TextOptions.TextFormattingMode="Ideal" 
        TextOptions.TextRenderingMode="Auto"        
        Background="{DynamicResource MaterialDesignPaper}"
        FontFamily="{DynamicResource MaterialDesignFont}"
        Title="MainWindow" Height="450" Width="600">

        <!--All of the above is meant to apply Material Design to the entire Window-->

    <StackPanel>
        <StackPanel.Resources>

            <!--This style overrides the Material Design style entirely,
            instead of just Margin and Horizontal Alignment--> 
            <Style x:Key="SpacedButton" TargetType="Button">
                <Setter Property="Margin" Value="0 10"/>
                <Setter Property="HorizontalAlignment" Value="Center"/>
            </Style>
        </StackPanel.Resources>

        <!--Material Design only works by applying properties directly to elements-->
        <Button Content="Button #1" HorizontalAlignment="Center" Margin="0 10"/>
        <Button Content="Button #2" Style="{DynamicResource SpacedButton}"/>
        <Button Content="Button #3" Style="{DynamicResource SpacedButton}"/>
        <Button Content="Button #4" HorizontalAlignment="Center" Margin="0 10"/>
    </StackPanel>
</Window>

As you can see, only elements with inline properties keep the MaterialDesign style, but by applying a custom style, the MaterialDesign style is lost.

How can I make sure that MaterialDesign is applied to every element, while still being able to override specific properties with custom styles?

Sorry if some of the terminology is wrong, I'm pretty new to WPF.


Solution

  • Use Style.BasedOn to inherit properties from whichever other style is in scope:

    <Style TargetType="{x:Type Button}" BasedOn="{StaticResource {x:Type Button}}">
        ...etc....
    

    Or a specific one:

    <Style x:Key="ThisStyleKey" TargetType="{x:Type Button}" BasedOn="{StaticResource OtherStyleKey}">
        ...etc....