wpfxamldictionaryxaml-resources

WPF Separating styles that depend on other styles into their own resource dictionary


I'm working on a C# MEF/Caliburn.Micro application that has some resource dictionaries for styles, colors, etc. I'm trying to give each style its own file, and I'm running into a problem with styles that are based on styles in other resource dictionaries. All of the application wide resources live in the Infastructure project, which are merged up into App.xaml.

Here's my solution layout:

Solution

  ->Shell
    App.xaml
    (other shell-related files)

  ->Infastructure
    ->ResourceDictionaries
      ->Brushes
          DefaultColorTheme.xaml
      ->ControlStyles
          ButtonStyle.xaml
          DeleteButtonStyle.xaml
          EditButtonStyle.xaml
      ResourceLibrary.xaml

ResourceLibrary.xaml is a merger of all the resource dictionaries within the ResourceDictionaries folder.

ResourceLibrary.xaml

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ResourceDictionary.MergedDictionaries>
  <ResourceDictionary Source="Brushes/DefaultColorTheme.xaml"/>
  <ResourceDictionary Source="ControlStyles/ButtonStyle.xaml"/>
  <ResourceDictionary Source="ControlStyles/DeleteButtonStyle.xaml"/>
  <ResourceDictionary Source="ControlStyles/EditButtonStyle.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>

ResourceLibrary.xaml gets merged into App.xaml

App.xaml

<Application...
         >
<Application.Resources>
  <ResourceDictionary>
     <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary Source="/Infastructure;component/ResourceDictionaries/ResourceLibrary.xaml"/>
        <ResourceDictionary>
           <local:Bootstrapper x:Key="Bootstrapper"/>
        </ResourceDictionary>
        </ResourceDictionary.MergedDictionaries>
  </ResourceDictionary>
 </Application.Resources>
</Application>

ButtonStyle.xaml contains my main button style that targets ButtonBase, and two anonymous styles that apply the main button style to Button and ToggleButton

ButtonStyle.xaml

<Style x:Key="ButtonStyle" TargetType="{x:Type ButtonBase}">
  ...
</Style>

<Style BasedOn="{StaticResource ButtonStyle}" TargetType="{x:Type Button}"/>
<Style BasedOn="{StaticResource ButtonStyle}" TargetType="{x:Type ToggleButton}"/>

This works fine. All Buttons and ToggleButtons in the get applied the style.

I have two other button styles that are used heavily through the application, DeleteButtonStyle and EditButtonStyle, that need to be based on ButtonStyle. Here's a code snip from DeleteButtonStyle.xaml. EditButtonStyle is similar.

<Style x:Key="DeleteButtonStyle" TargetType="{x:Type ButtonBase}" BasedOn="{StaticResource ButtonStyle}">
 ....
</Style>

Everything works at design time. The buttons get the ButtonStyle style, and buttons marked explicitly with ...Style="{DynamicResource DeleteButtonStyle}"... get the DeleteButtonStyle applied to them. However, at run time, I always get the following exception:

System.Windows.Markup.XamlParseException occurred
 HResult=-2146233087
 Message='Provide value on 'System.Windows.Markup.StaticResourceHolder' threw an exception.' Line number '4' and line position '35'.
  Source=PresentationFramework
  LineNumber=4
  LinePosition=35
  StackTrace:
    at System.Windows.Markup.WpfXamlLoader.Load(XamlReader xamlReader, IXamlObjectWriterFactory writerFactory, Boolean skipJournaledProperties, Object rootObject, XamlObjectWriterSettings settings, Uri baseUri)
    at System.Windows.Markup.WpfXamlLoader.LoadBaml(XamlReader xamlReader, Boolean skipJournaledProperties, Object rootObject, XamlAccessLevel accessLevel, Uri baseUri)
    at System.Windows.Markup.XamlReader.LoadBaml(Stream stream, ParserContext parserContext, Object parent, Boolean closeStream)
    at System.Windows.Application.LoadComponent(Object component, Uri resourceLocator)
    ...
 InnerException: 
   HResult=-2146233088
   Message=Cannot find resource named 'ButtonStyle'. Resource names are case sensitive.
   Source=PresentationFramework
   StackTrace:
        at System.Windows.StaticResourceExtension.ProvideValueInternal(IServiceProvider serviceProvider, Boolean allowDeferredReference)
        at System.Windows.StaticResourceExtension.ProvideValue(IServiceProvider serviceProvider)
        at MS.Internal.Xaml.Runtime.ClrObjectRuntime.CallProvideValue(MarkupExtension me, IServiceProvider serviceProvider)
   InnerException:

If I move DeleteButtonStyle and EditButtonStyle into the same file where ButtonStyle is (ButtonStyle.xaml), like so

<Style x:Key="ButtonStyle" TargetType="{x:Type ButtonBase}">
  ...
</Style>

<Style BasedOn="{StaticResource ButtonStyle}" TargetType="{x:Type Button}"/>
<Style BasedOn="{StaticResource ButtonStyle}" TargetType="{x:Type ToggleButton}"/>

<Style x:Key="DeleteButtonStyle" TargetType="{x:Type ButtonBase}" BasedOn="{StaticResource ButtonStyle}">
 ....
</Style>
<Style x:Key="EditButtonStyle" TargetType="{x:Type ButtonBase}" BasedOn="{StaticResource ButtonStyle}">
 ....
</Style>

then everything works.

How can I separate styles that depend on other styles into their own resource dictionary?


Solution

  • In your DeleteButtonStyle and EditButtonStyle

      <ResourceDictionary Source="ControlStyles/DeleteButtonStyle.xaml"/>
      <ResourceDictionary Source="ControlStyles/EditButtonStyle.xaml"/>
    

    You have to explicitly merge again the ResourceDictionary inside the two file to load the ButtonStyle.

    So

    <ResourceDictionary>
         <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="/Infastructure;component/ResourceDictionaries/ButtonStyle.xaml"/>
         </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>