Search code examples
c#wpfxamltemplatesresourcedictionary

How can I make a Custom Control automatically apply a style defined in a resource dictionary?


I have a control library with a custom control :

public class GlassButton : Button {
}

and I have also defined a resource dictionary to style the control :

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:Animations="clr-namespace:WPFTools.Classes"
    xmlns:Controls="clr-namespace:WPFTools.Controls"
    xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
    xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
    mc:Ignorable="d">
    <Style TargetType="{x:Type Controls:GlassButton}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type Button}">

I want to be able to simply drag and drop the GlassButton onto a window or control and NOT have to do this :

<Window.Resources>
    <ResourceDictionary Source="Foo"/>
</Window.Resources>

I've been able to do this once before but that knowledge seems to have been lost to me.

How can I make this happen? ( I'm fine making changes in the code behind of my control ).


Solution

  • I had to re-remember how this worked a week ago, and this is what I had to do to make it work for me. The typical way with custom controls is to define the style in a file named generic.xaml located in the Themes folder directly beneath your project root. Then you need to override the default style in the static constructor of your custom control class. It would look something like this:

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

    Finally, you need to set the appropriate assembly property to say that your generic theme is located within your assembly. Something like this would go in your Properties\AssemblyInfo.cs file:

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

    I'm not sure if this is strictly necessary, but I also had to change the Build Action property on my generic.xaml file to Page before the default style would get properly applied to my control.