0

I have an application that uses several custom themes that can be switched at runtime. The themes, the application and the UI (UserControls, dialogs etc.) each are in a separate .NET assembly.

The themes not only override the implicit default styles of controls (new control template), but also provide various explicit styles.

Example:

<!-- "Themes" assembly -->
<Style TargetType="Button" x:Key="DialogButtonStyle" 
       BasedOn="{StaticResource BaseButtonStyle}">
    <Setter Property="HorizontalAlignment" Value="Left" />
    <Setter Property="Height" Value="24" />
    <Setter Property="MinWidth" Value="86" />
    <Setter Property="Padding" Value="8 0" />
</Style>

<!-- "UI" assembly -->
<Button Style="{DynamicResource DialogButtonStyle}"
        Content="OK" />

Themes are applied by merging all their styles, brushes etc. into the application resources, e.g.:

<Application x:Class="GUIDemo.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             StartupUri="MainWindow.xaml">
    <Application.Resources>    
        <ResourceDictionary x:Name="MainDictionary">
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary x:Name="ThemeDictionary">
                    <ResourceDictionary.MergedDictionaries>
                        <ResourceDictionary Source="/Themes;component/SystemTheme.xaml" />
                    </ResourceDictionary.MergedDictionaries>
                </ResourceDictionary>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>    
    </Application.Resources>
</Application>

(Or corresponding code at runtime.)

Question:

Is it possible to define fallback styles in my UI assembly (not the application assembly)? These should be automatically applied if the application has not included any of the themes, i.e. when keys like "DialogButtonStyle" are undefined and cause error messages in the output.

What I want to achieve is that my UI library is fully themable, but can also be used without having to care about the custom themes.

What I tried:

(1) Define a dummy App.xaml that contains the fallback style. This works at design time (designer preview, code completion) but not at runtime.

(2) Define the styles in "Themes/Generic.xaml". This seems to work only for implicit styles, not explicit styles.

(3) Merge the Generic.xaml into the resources of all XAML files that use the style. This does not work because the style now overrides the theme.

Sebastian Negraszus
  • 11,915
  • 7
  • 43
  • 70

2 Answers2

0

Try to merge the fallback styles into your ResourceDictionary before you merge the theme resources:

<Application.Resources>
    <ResourceDictionary x:Name="MainDictionary">
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="FallbackResources.xaml" />
            <ResourceDictionary Source="/Themes;component/SystemTheme.xaml" />
        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
</Application.Resources>

Then the theme resources - if any - should override the fallback resources.

No, that's not what I meant. I want the fallbacks to be defined in the UI assembly (not the application). The whole point of the fallbacks is to make sure the styles are defined even if an application does properly apply the theme (or other resource files).

There is no way for the application to be able to apply these fallback resources unless you merge them into your application. If the application fails to apply any resource dictionary from the external assembly you will get runtime exceptions if you try to reference any of these resources in your views. The resources must be explicitly merged into the application somehow.

mm8
  • 163,881
  • 10
  • 57
  • 88
  • No, that's not what I meant. I want the fallbacks to be defined in the UI assembly (not the application). The whole point of the fallbacks is to make sure the styles are defined even if an application does properly apply the theme (or other resource files). – Sebastian Negraszus Dec 23 '16 at 13:47
  • No then. You need to explicitly tell the application that these resources actually exist and where to find them. I edited my answer. – mm8 Dec 23 '16 at 14:03
  • @mm8 This doesn't seem right, there are several standard WPF controls (TextBox for example) that have default colors. In my case I'm building a control that uses Grids which seem to have a default color of Transparent which is not desired in this case. I think it has to do with templating, there must be a default template or something. – Scott Solmer May 01 '20 at 05:13
0

I too am building a control library that supports themes and ran into this issue. You want someone to be able to use the control in a project that doesn't define any themes (and not look weird), but at the same time support theme colors.

When no theme is added to an App's resources, the theme colors (resource keys) aren't found and the controls revert to their defaults. For example, black text on white background for a TextBox. In the case of a Grid, it is transparent and that is a problem for a pop-up control based on grid.

The solution is an Implicit Style.

Basically you define a style at the level you need it (for example in the grid, or at the control level) which targets a specific type and does not use an x:key.

Related question:
Implicit styles in Application.Resources vs Window.Resources?

Scott Solmer
  • 3,871
  • 6
  • 44
  • 72