Search code examples
c#wpftemplatesstyles

How to organize resources (styles, ...) in a complex WPF scenario?


How can WPF resources - including styles, templates, etc. - be organized, so that I can use them across Windows, Pages or even Projects. What options do I have to achieve maximum re-usability of my resources and a maintainable structure (for example one file per Template)?

For example: I am creating a WPF application and I want to use a TabControl, but I want to make major changes to it. So I could create a style in and apply it to the TabControl and TabItem. That's ok, but where can I place my resources to keep my Window XAML clear and have the style accessible from other Windows or projects as well?

I found that I can add it to App.xaml but that is only a solution for one project and allows sharing just between items of this project. Also, I think it would be better to have these templates a little separate from other code, than placing it all in some page or app.xaml?


Solution

  • I usually create a seperate styling project, which I reference from the projects, which I want to style. The styling project has a fixed structure like this:

    Styling project

    For every control, I create a styling ResourceDictionary. For example for my buttons:

    <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
        <Style x:Key="PrimaryButtonStyle" TargetType="Button">
        </Style>
    
        <Style x:Key="ToolbarButton" TargetType="Button">
            <Setter Property="BorderThickness" Value="0" />
            <Setter Property="Margin" Value="3"/>
            <Setter Property="Background" Value="Transparent"></Setter>
        </Style>
    </ResourceDictionary>
    

    In one main ResourceDictionary, I merge all the other dictionaries, in this case in the file IncaDesign.xaml, which you can see in the picture above:

    <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                        xmlns:controls="clr-namespace:Commons.Controls;assembly=Commons">
    
        <ResourceDictionary.MergedDictionaries>
    
            <ResourceDictionary Source="Converter/Converter.xaml" />
            <ResourceDictionary Source="Styles/Button.xaml" />
            <ResourceDictionary Source="BitmapGraphics/Icons.xaml" />
    
        </ResourceDictionary.MergedDictionaries>
    
        <!-- Default Styles -->
        <Style TargetType="Button" BasedOn="{StaticResource PrimaryButtonStyle}"></Style>
    </ResourceDictionary>
    

    Notice how I defined the default styles, which are applied automatically, unless you specify otherwise. In every window or control, that you want to style, you only need to reference this one ResourceDictionary. Note the definition of the source, which is a reference to the assembly (/Commons.Styling;component...)

    <UserControl.Resources>        
        <ResourceDictionary>            
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="/Commons.Styling;component/IncaDesign.xaml" />
            </ResourceDictionary.MergedDictionaries>   
        </ResourceDictionary>        
    </UserControl.Resources>
    

    Default styles will be set automatically now, and if you want to access a resource explicitly, you can do this, using StaticResource.

    <Viewbox Height="16" Width="16" Margin="0,0,10,0">
        <ContentControl Content="{StaticResource FileIcon32}" />
    </Viewbox>
    

    This is very nice solution in my opinion, which works for very complex solutions, including modular solutions, for example built with PRISM.