Search code examples
c#.netwpfwpf-style

Reuse of styles and templates


I have been working on several Wpf projects. In every project we needed to style the default Wpf controls (e.g. Button). Everytime we started on a new project we built our templates and styles from scratch - or simply copied them from one assembly to another.

Because I hate copying and recreating the same code over and over again I want to collect those styles and move them into one place so I can use them across multiple projects with much less effort.

An example of modification (again using the Button control): We need to change brushes of different button states to fit the requirements for the application.

            | Hover-Brush | Click-Effect   | 
|-----------|-------------|----------------|
| Project A | Orange      | Light Orange   |
| Project B | Blue        | Light Blue     |
| ...       | ...         | ...            |

In order to achieve my goal I need to abstract this samplestyle:

<Style TargetType="{x:Type Button}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type Button}">
                <Border x:Name="Border" Background="Orange">
                    <!-- Further elements required to build our button -->
                </Border>

                <ControlTemplate.Triggers>
                    <Trigger Property="IsMouseOver" Value="True">
                        <Setter TargetName="Border" Property="Background" Value="LightOrange" />
                    </Trigger>
                    <!-- Further triggers for other effects -->
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>   
</Style>

As you can see the colors are hardcoded and due to that the style is not reusable. My idea is to use attached properties the style can use for binding. If I would define an attached property HoverBrush and use it for binding the new style would look like this:

<Style TargetType="{x:Type Button}"
       x:Key="DefaultButton">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type Button}">
                <Border x:Name="Border" Background="{TemplateBinding Background}">
                    <!-- Further elements required to build our button -->
                </Border>

                <ControlTemplate.Triggers>
                    <Trigger Property="IsMouseOver" Value="True">
                        <Setter TargetName="Border" 
                                Property="Background" 
                                Value="{Binding Path=styles:Brushes.HoverBrush, 
                                                RelativeSource={RelativeSource TemplatedParent}, 
                                                FallbackValue={StaticResource SomeBrush}}" />
                    </Trigger>
                    <!-- Further triggers for other effects -->
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>   
</Style>

This style would reduce the markup required for a new theme in a different application to something like this:

<Style TargetType="{x:Type Button}"
       BasedOn="{StaticResource DefaultButton}">
    <Setter Property="styles:Brushes.HoverBrush"
            Value="LightOrange" />
</Style>

So my question(s) would be: Are there different approaches? Do you see some negative sides to my approach? And most important: Do you know more effective ways to achieve my goal?


Solution

  • Since each new app will be themed I would just define some brushes in Generic.xaml and do {DynamicResource HoverBrush}.

    The xaml for the button style could stay the same, and in each new app you would just need to define new brushes with those same names in Generic.xaml