44

I have a library, CommonLibraryWpfThemes, with several Resource Dictionary XAML files in it. My Themes/Generic.xml file contains a ResourceDictionary.MergedDictionaries declaration that merges all the other files together.

Generic.xaml

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary
            Source="/CommonLibraryWpfThemes;component/ResourceDictionaries/BrushDictionary.xaml" />
        <ResourceDictionary
            Source="/CommonLibraryWpfThemes;component/ResourceDictionaries/TextBlockDictionary.xaml" />
        <ResourceDictionary
            Source="/CommonLibraryWpfThemes;component/ResourceDictionaries/LabelDictionary.xaml" />
        <ResourceDictionary
            Source="/CommonLibraryWpfThemes;component/ResourceDictionaries/ButtonDictionary.xaml" />
        <ResourceDictionary
            Source="/CommonLibraryWpfThemes;component/ResourceDictionaries/WindowDictionary.xaml" />
    </ResourceDictionary.MergedDictionaries>
</ResourceDictionary>

In my application project, I have a reference to CommonLibraryWpfThemes, and I explicitly reference Generic.xml in my App.xaml file.

App.xaml -- FAILS

<Application
    x:Class="MyApp.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Application.Resources>
        <ResourceDictionary
            Source="/CommonLibraryWpfThemes;component/Themes/Generic.xaml" />
    </Application.Resources>
</Application>

This doesn't work. I get the following error when I run my app:

System.Windows.Markup.XamlParseException occurred
  Message="Cannot find resource named '{_fadedOrangeBrush}'. Resource names are case sensitive.  Error at object 'System.Windows.Setter' in markup file 'CommonLibraryWpfThemes;component/ResourceDictionaries/WindowDictionary.xaml' Line 18 Position 13."
  Source="PresentationFramework"
  LineNumber=18
  LinePosition=13

If I place the contents of Generic.xaml into App.xaml directly, everything works fine:

App.xaml -- SUCCEEDS

<Application
    x:Class="MyApp.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary
                    Source="/CommonLibraryWpfThemes;component/ResourceDictionaries/BrushDictionary.xaml" />
                <ResourceDictionary
                    Source="/CommonLibraryWpfThemes;component/ResourceDictionaries/TextBlockDictionary.xaml" />
                <ResourceDictionary
                    Source="/CommonLibraryWpfThemes;component/ResourceDictionaries/LabelDictionary.xaml" />
                <ResourceDictionary
                    Source="/CommonLibraryWpfThemes;component/ResourceDictionaries/ButtonDictionary.xaml" />
                <ResourceDictionary
                    Source="/CommonLibraryWpfThemes;component/ResourceDictionaries/WindowDictionary.xaml" />
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
</Application>

Maybe I'm going about this in the wrong way. My goal is to make it easy to reference all my theme resources from multiple applications without having to list out all the individual files. Is there a recommended way to do this? (Note: I'm not trying to switch between multiple themes--I just have one theme.)

As a bonus, it would be nice if someone could tell me how to reference resources in an external library without breaking the designer in Visual Studio.

Thanks.

EDIT:

I tried wrapping the ResourceDictionary in a ResourceDictionary.MergedDictionary element, but that also didn't work (I get the same error):

<Application
    x:Class="MyApp.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary
                    Source="/CommonLibraryWpfThemes;component/Themes/Generic.xaml" />
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
</Application>
devuxer
  • 41,681
  • 47
  • 180
  • 292
  • 1
    I'll start a small bounty here. Combining a few RessourceDictionaries into a Theme (and just loading this in App.xaml) seems a common enough scenario... – Jens Nov 11 '10 at 08:56

5 Answers5

68

Answered a similar question here earlier, see Adding a Merged Dictionary to a Merged Dictionary question.

This is an optimization bug, see Microsoft Connect / DefaultStyleKey style not found in inner MergedDictionaries:

On the creation of every object in XAML, if a default style is present (i.e. style w/ a key of Type) that style should be applied. As you can imagine there are several performance optimizations to make that (implied) lookup a light weight as possible. One of them is that we don’t look inside Resource Dictionaries unless they are flagged as “containing default Styles”. There is a bug: if all your default styles are nested in merged dictionaries three levels deep (or deeper) the top dictionary does not get flagged so the search skips it. The work around is to put a default Style to something, anything, in the root Dictionary.

So adding a dummy style to the root dictionary fixes this. Example

<Application x:Class="MyApp.App"  
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"  
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">  
    <Application.Resources> 
        <ResourceDictionary> 
            <ResourceDictionary.MergedDictionaries> 
                <ResourceDictionary 
                    Source="/CommonLibraryWpfThemes;component/Themes/Generic.xaml" /> 
                </ResourceDictionary.MergedDictionaries> 
            <!-- Dummy Style, anything you won't use goes --> 
            <Style TargetType="{x:Type Rectangle}" /> 
        </ResourceDictionary> 
    </Application.Resources> 
</Application>   
Community
  • 1
  • 1
Fredrik Hedblad
  • 83,499
  • 23
  • 264
  • 266
14

Check your constructor in App.xaml.cs calls InitializeComponent() - this is what merges the resource dictionaries...

Chris
  • 1,241
  • 1
  • 14
  • 33
  • 2
    This was very helpful for me. I was trying to figure out why my Pages (hosted in a Frame) weren't getting the resources defined in my App.xaml. It turns out that the constructor wasn't calling InitializeComponent. Thanks Chris!!!! – NathanAW Feb 25 '10 at 19:09
5

You should not have to reference generic.xaml at all, it has built-in support. This however means that it provides default styling, which you do not set explicitly. Explicitly set styles/templates need to be attainable from explicitly referenced res dictionaries.

(EDIT for clarity)

One exception to this is the App.xaml, where defined resources become accessible by the whole app, without requiring to reference any specific resource dictionary. The resource itself, would have to be accessible by name.

The reason why this fails

<Application.Resources>
    <ResourceDictionary
        Source="/CommonLibraryWpfThemes;component/Themes/Generic.xaml" />
</Application.Resources>

is, I think, because you didn't wrap it in a MergedDictionary wrapper, adding it to merged dictionaries. Adding directly to resources works only for resources you declare locally, e.g. the styles, etc. themselves.

However, as I said before, you shouldn't have to merge generic.xaml anywhere, maybe you should just refactor brushes and other resources used outside styles, and merge only those resources in app.xaml.

Also note that styles do not have to be in generic.xaml to have "default style" behaviour - if a style with key equal to the type of the element is accessible to it (globally, or in local resources), then it will use the style as a default style. The generic.xaml is just a convenience.

Check this answer.

For other custom brushes, etc, you need to reference those resources explicitly.

You should also check the contents of the WindowDictionary.xaml, this error has a certain smell about it.

Community
  • 1
  • 1
Kenan E. K.
  • 13,955
  • 3
  • 43
  • 48
  • So I think you're saying that referencing the ResourceDictionaries directly in App.xaml is necessary and the only way it will work. I.e., there's no way I can "pre-merge" all my dictionaries and just reference the pre-merged entity from App.xaml. Not as convenient, but if that's how it works, it's not the end of the world. So far, I *always* set my Styles attributes explicitly using `{StaticResource MyResourceName}`, so I guess I would have to refactor a lot of stuff to take advantage of the default behavior that Generic.xaml allows. Do I have that right? – devuxer Aug 04 '09 at 22:35
  • When you merge dictionaries with app.xaml, you make the resources "global", accessible by the whole app (as the name states). Resources in app.xaml do not need to be referenced via dictionary name, only via specific resource key, I may have been unclear on that, I will clarify the answer. I usually create grouped merged dictionaries for different parts of the app and reference that dictionary in xaml as required. – Kenan E. K. Aug 05 '09 at 10:53
  • Thanks for clarifying your answer, but either I'm misinterpreting what you mean by "wrap it in a `MergedDictionary` wrapper" or that doesn't work either. I put an edit at the bottom of my question with a code sample. – devuxer Aug 05 '09 at 18:20
  • Yep, you did it right, although I'm not sure why it doesn't work. Maybe it is some bug directly related to the generic.xaml. Try merging some other dictionary to the same place and using some resource from it, just to see will it work. – Kenan E. K. Aug 05 '09 at 21:05
  • Doesn't work if I paste the code into a different file (MergedDictionary.xaml) either :( – devuxer Aug 05 '09 at 22:20
0

I was getting this error in my unit tests and Chris' answer from above gave me the clue I needed. Basically on my first tested method, I put:

        MyApplication.App app = new MyApplication.App();
        app.InitializeComponent();

And suddenly it could find my template for my pages. Note: this does mean that you have to check to see if an instance of your App already exists if you are unit testing your App.cs as well.

ouflak
  • 2,458
  • 10
  • 44
  • 49
-1

My solution is here, click Workarounds.

abatishchev
  • 98,240
  • 88
  • 296
  • 433
Siarhei Kuchuk
  • 5,296
  • 1
  • 28
  • 31
  • 2
    Voted down for: Link without link text; no explanation whatsoever; external content - no control over the content. – trapicki Aug 05 '14 at 09:18