ygoe
ygoe

Reputation: 20374

Apply default Button style to custom Button class

I've created a custom IconButton class that inherits from Button and adds a few dependency properties to place an image in front of the button's text.

The code begins like this:

public partial class IconButton : Button
{
    // Dependency properties and other methods
}

It comes with a XAML file that looks like this:

<Button x:Class="Unclassified.UI.IconButton" x:Name="_this" ...>
    <Button.Template>
        <ControlTemplate>
            <Button
                Padding="{TemplateBinding Padding}"
                Style="{TemplateBinding Style}"
                Focusable="{TemplateBinding Focusable}"
                Command="{TemplateBinding Button.Command}">

                <StackPanel ...>
                    <Image .../>
                    <ContentPresenter
                        Visibility="{Binding ContentVisibility, ElementName=_this}"
                        RecognizesAccessKey="True"
                        Content="{Binding Content, ElementName=_this}">
                        <ContentPresenter.Style>
                            ...
                        </ContentPresenter.Style>
                    </ContentPresenter>
                </StackPanel>
            </Button>
        </ControlTemplate>
    </Button.Template>
</Button>

That works well so far. (But if you know a simpler way to override a Button's content without changing the entire template and placing a Button within the Button, please let me know. Every time I tried, Visual Studio 2010 SP1 immediately crashed the moment I closed the final XML tag.)

Now I've added some code to fix WPF's broken Aero2 theme for Windows 8. It's a separate ResourceDictionary that overwrites all sorts of default styles: (Based on this, via here)

<ResourceDictionary ...>
    <Style TargetType="{x:Type Button}">
        ...
    </Style>
</ResourceDictionary>

The new ResourceDictionary is added to the Application Resources on startup, in App.xaml.cs:

protected override void OnStartup(StartupEventArgs args)
{
    base.OnStartup(e);
    // Fix WPF's dumb Aero2 theme if we're on Windows 8 or newer
    if (OSInfo.IsWindows8OrNewer)
    {
        Resources.MergedDictionaries.Add(new ResourceDictionary
        {
            Source = new Uri("/Resources/RealWindows8.xaml", UriKind.RelativeOrAbsolute)
        });
    }
    ...
}

This also works well for normal Button controls I place in my XAML views. (I'm still looking for a method to find out the real Windows theme instead of relying on the version number.)

But my IconButton control doesn't consider these new defaults and is still based on WPF's built-in Button style which is very basic. (It's really just a tight rectangle without all the details and interactivity that Win32 shows.)

I guess I need a way to tell my IconButton that it should re-evaluate the base style and see the newly added RealWindows8 styles. How can I do that?

Upvotes: 1

Views: 1383

Answers (1)

ygoe
ygoe

Reputation: 20374

I found the solution. There are two ways to accomplish this. Either one is sufficient.

The XAML way:

Add the Style attribute to the derived control. This presets the new control's style explicitly to whatever has been defined in the application as the Button style. StaticResource is sufficient for this. If a different Style is specified where the derived control is used, that will replace this initial value.

<Button Style="{StaticResource {x:Type Button}}" ...>
    ...
</Button>

The code(-behind) way:

Call the SetResourceReference method in the constructor of the derived class.

public IconButton()
{
    // Use the same style as Button, also when it is overwritten by the application.
    SetResourceReference(StyleProperty, typeof(Button));
    ...
}

I've tested this for my IconButton as well as a derived TabControl and TabItem class.

(Source)

Upvotes: 1

Related Questions