wpfxamlstylescontrols

Derived control not picking up base style


I can create a derived Button class like the following, and I will automatically get the style from the default Button

public class Button2 : Button
{ 
}

However, I cannot seem to do the same with a custom control

public class X : ContentControl
{
    static X()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(X), new FrameworkPropertyMetadata(typeof(X)));
    }
}

public class Y : X
{

}
<Window.Resources>
    <Style TargetType="{x:Type local:X}">
        <Style.Setters>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type local:X}">
                        <Border Background="Red">
                            <ContentPresenter />
                        </Border>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style.Setters>
    </Style>
</Window.Resources>

<StackPanel>
    <local:X>
        <TextBlock Text="Hello world!" />
    </local:X>

    <local:Y>
        <TextBlock Text="Hello world!" />
    </local:Y>

    <local:Button2>
        <TextBlock Text="Hello world!" />
    </local:Button2>
</StackPanel>

The above code will show nothing for the Y control. I would expect it to pick up the style from X

Please note, I do not want to have to define a style for Y, I want it to behave like Button2 where it picks up the base style without having to add anything to the Y class.

I have had a look in the source for Button here : https://github.com/dotnet/wpf/blob/main/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/Button.cs

but can't see anything special.

One workaround I have seen is to use :

public class X : ContentControl
{
    public X()
    {
        SetResourceReference(StyleProperty, typeof(X));
    }
}

But I am wondering why I don't see anything similar in the Button source?


Solution

  • The default control Style should be declared in the file Themes\Generic.xaml, which is automatically created if you add a Custom Control (WPF) item to your Visual Studio project.

    It would look like this:

    <ResourceDictionary
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:CustomControlStyleTest">
        <Style TargetType="{x:Type local:X}">
            <Style.Setters>
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="{x:Type local:X}">
                            <Border Background="Red">
                                <ContentPresenter />
                            </Border>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style.Setters>
        </Style>
    </ResourceDictionary>
    

    Visual Studio then also creates an AssemblyInfo.cs file with this content:

    using System.Windows;
    
    [assembly: ThemeInfo(
        ResourceDictionaryLocation.None,
        ResourceDictionaryLocation.SourceAssembly
    )]
    

    Having that, your class Y would pick up the default Style from X.