Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Loading merged ResourceDictionary from different assembly fails

Tags:

c#

.net

wpf

xaml

I've put all of my application's ResourceDictionaries into a separate assembly and merged them into one ResourceDictionary which I want to include as a resource in my application:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary Source="InputStyles.xaml"/>
        <ResourceDictionary Source="DataGridStyles.xaml"/>
        <ResourceDictionary Source="ComboboxStyles.xaml"/>
        <ResourceDictionary Source="CheckboxStyles.xaml"/>
        <ResourceDictionary Source="TabControlStyles.xaml"/>
        <ResourceDictionary Source="ButtonStyles.xaml"/>
    </ResourceDictionary.MergedDictionaries>
</ResourceDictionary>

Declaring resource:

<Window.Resources>
    <ResourceDictionary Source="pack://application:,,,/StyleAssembly;component/Styles.xaml"/>
</Window.Resources>

Looking at the designer in VS all controls are displayed with the styles from the files but when I try to start the application I'm getting the following error:

"Cannot locate resource 'inputstyles.xaml'."

The build action is set to 'Page' for all files and the build for both projects succeeds. What am I doing wrong?

like image 386
chaosr Avatar asked Dec 12 '11 14:12

chaosr


3 Answers

From my observation. Setting the resource dictonary build style to Resource can cause bizarre errors further down the road (I suddenly started getting runtime errors Cannot create X where X was a user defined type referenced in my resource dictionary).

I recommend leaving the build style at Page. From what I've seen this should work just fine.

like image 121
sasha Avatar answered Oct 03 '22 21:10

sasha


The build action should be defined as Resource or Content if you are willing to do some of the leg work.

Your resource must be defined as part of the project as a Resource build action. If you include a resource .xaml file in the project as Resource, you do not need to copy the resource file to the output directory, the resource is already included within the compiled application. You can also use Content build action, but you must then copy the files to the output directory and also deploy the resource files in the same path relationship to the executable.

like image 20
Aaron McIver Avatar answered Oct 03 '22 19:10

Aaron McIver


See this solution for both cases when you know the external Assembly structure (file names etc.) and when you don't know and just want to iterate an external Assembly for ResourceDictionary(s) or UserControls.

Both XMAL and C# solution.

Update

XAML Way: If you know the URI of the resource in an Assembly, then load it directly. Transform same syntax in XAML

ResourceDictionary dictionary = new ResourceDictionary();
 dictionary.Source = new Uri("pack://application:,,,/WpfControlLibrary1;Component/RD1.xaml", UriKind.Absolute);
 foreach (var item in dictionary.Values)
 {
    //operations
 }

C# Way: If you only know the Assambly and don't know the Resources in it

public ResourceDictionary GetResourceDictionary(string assemblyName)
{
    Assembly asm = Assembly.LoadFrom(assemblyName);
    Stream stream = asm.GetManifestResourceStream(asm.GetName().Name + ".g.resources");            
    using (ResourceReader reader = new ResourceReader(stream))
    {
        foreach (DictionaryEntry entry in reader)
        {
            var readStream = entry.Value as Stream;
            Baml2006Reader bamlReader = new Baml2006Reader(readStream);
            var loadedObject = System.Windows.Markup.XamlReader.Load(bamlReader);
            if (loadedObject is ResourceDictionary)
            {
                return loadedObject as ResourceDictionary;
            }
        }
    }
    return null;
}
like image 34
Kylo Ren Avatar answered Oct 03 '22 20:10

Kylo Ren