Ryszard Dżegan
Ryszard Dżegan

Reputation: 25414

Inversion of inheritance in WPF styles

I've got a UserControl that contains a button:

<Button Content="Button"/>

And a style:

<Style TargetType="Button">
    <Setter Property="Background" Value="Blue"/>
</Style>

The parent window (or another UserControl) may set another more general style:

<Style TargetType="Button">
    <Setter Property="Background" Value="Red"/>
</Style>

The result is (what is obvious) that parent buttons will have more general style (Red) and my user control will have buttons with more specific style (Blue).


I'm wondering how to invert such behaviour in order to achieve something like setting the default style in my custom user control which could be then overriden in parent control or window if necessary?

The key is, that default style is defined first in custom user control and it is overriden automaticly by its parent. That is way I called it an inversion.


The imaginary example of the solution maight look like the following:

<Style TargetType="Button" StylePriority="Default">
    <Setter Property="Background" Value="Blue"/>
</Style>

The StylePriority could indicate that if there is no other style defined for that button, then the default style should be applied to it.

Upvotes: 3

Views: 441

Answers (2)

Cameron MacFarland
Cameron MacFarland

Reputation: 71856

Create a dependency property in your UserControl for the buttons colour, and then bind to it. You can specify a default value of blue for that property.

public static readonly DependencyProperty ButtonColorProperty = 
    DependencyProperty.Register("ButtonColor", typeof(Color), typeof(MyUserControl),
    new PropertyMetadata(Colors.Blue));

public Color State
{
    get { return (Color)this.GetValue(ButtonColorProperty); }
    set { this.SetValue(ButtonColorProperty, value); } 
}

<UserControl ...
             x:Name="root">
    <Button Content="Button" Background="{Binding ElementName=root, Path=ButtonColor}" />
</UserControl>

Then set that property to red where you want to use the UserControl.

<local:MyUserControl ButtonColor="Red" />

Upvotes: 1

aligator
aligator

Reputation: 450

You could use dynamic resources.

A UserControl:

<UserControl x:Class="Example.UserControl1"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:Example">
    <UserControl.Resources>
        <Style TargetType="local:UserControl1">
            <Style.Resources>
                <Style TargetType="Button" x:Key="UserControl1.DefaultButtonStyle">
                    <Setter Property="Background" Value="Red"/>
                </Style>
            </Style.Resources>
        </Style>
    </UserControl.Resources>

    <Button Content="UserControlButton" Style="{DynamicResource UserControl1.DefaultButtonStyle}"/>
</UserControl>

And a Window:

<Window x:Class="Example.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:Example">

    <Window.Resources>
        <Style TargetType="Button">
            <Setter Property="Background" Value="Blue" />
        </Style>
    </Window.Resources>

    <StackPanel>
        <local:UserControl1 >
            <local:UserControl1.Resources>
                <Style x:Key="UserControl1.DefaultButtonStyle" TargetType="Button"
                    BasedOn="{StaticResource {x:Type Button}}">
                    <Setter Property="FontSize" Value="40" />
                </Style>
            </local:UserControl1.Resources>
        </local:UserControl1>
        <Button Content="WindowButton" />
    </StackPanel>
</Window>

If you remove the style for the control in the window, the default user control button style will be applied.

Upvotes: 6

Related Questions