2

I ran into a problem while developing a WPF application which is based on plugins using MEF.
Every plugin can have its own ResourceDictionary which includes different styles and colors. To let my main application (which loads all the plugins) know about all the different ResourceDictionaries I created a class for every dictionary and decorated the class with the [Export(typeof(ResourceDictionary))] attribute. In my main application I then import all exported ResourceDictionaries and add them to Application.Current.Resources.MergedDictionaries. So far everything is working fine.
The only thing which is bothering me is, that when referencing a resource in one of the views of the plugins I have to use DynamicResource in order to avoid VisualStudio to show an error message like:

The resource ... could not be resolved.

Even though at compiletime and runtime everything works fine.
To workround this issue of only using DynamicResource (because DynamicResource calls are more expensive than StaticResource calls) I added the ResourceDictionaries in every plugin-view I use them:

<UserControl.Resources>
   <ResourceDictionary>
      <ResourceDictionary.MergedDictionaries>
         <ResourceDictionary Source="/resources/ColorDictionary.xaml" />
         <ResourceDictionary Source="/resources/StyleDictionary.xaml" />
      </ResourceDictionary.MergedDictionaries>
   </ResourceDictionary>
</UserControl.Resources>

Now because I reference them relative to the path of the plugin-assembly I get error messages in my main application:

It can't find the file "resources/StyleDictionary.xaml"

Which is understandable because my main application doesn't has such a file.
Now to avoid this error I found a solution which is instead of:

<ResourceDictionary Source="/resources/ColorDictionary.xaml" />

I hand over the AssemblyShortName of the current plugin-assembly like this:

<ResourceDictionary Source="/MyAssemblyShortName;component/resources/SymbolDictionary.xaml" />

When doing it like this no errors are given and all resources getting loaded fine. BUT what if the AssemblyShortName gets changed over time (the project is still at the beginning of its development). If so I have to find all this references and change them by hand.

TL;DR / Question:
Is there another way instead of using the AssemblyShortName to reference the current assembly as an absolute path in XAML. Because this:

<ResourceDictionary Source="/My.Namespace.PluginAssembly;component/resources/SymbolDictionary.xaml" />

gives me the error:

Assembly is not referenced by this project.

(Of course not because the "assembly" is "this project")

croxy
  • 4,082
  • 9
  • 28
  • 46
  • 2
    Just from a design perspective - why does the main app have a direct dependency on items such as resource dictionaries in plug-ins? The whole idea of plug-ins is that the behavior of the app can be enhanced with plug-ins without changing the code of the app. Otherwise you may as well make them regular libraries and discard MEF. Better that the plug-ins are entirely self-contained, not just dictionaries but also any views. –  Apr 24 '17 at 11:28
  • The referencing of the `ResourceDictionaries` in the main application is capsulated from MEF. So I don't have to change any code in my main application when adding a new plugin. Besides that without merging the plugin dictionaries into the main application the references aren't found when using values form the dictionaries in the respective plugins during runtime. – croxy Apr 24 '17 at 11:51

1 Answers1

1

Is there another way instead of using the AssemblyShortName to reference the current assembly as an absolute path in XAML.

No, I don't think so. The name of the assembly is part of the pack URI: https://msdn.microsoft.com/en-us/library/aa970069(v=vs.110).aspx.

If you don't want to find all references and modify the them manually when you change the name of the assembly you could either avoid changing the name of the assembly altogether or add the resource dictionaries programmatically:

Set up application resources from code

Then you could easily get the assembly name dynamically:

Getting assembly name

Community
  • 1
  • 1
mm8
  • 163,881
  • 10
  • 57
  • 88
  • The problem with setting the `ResourceDictionaries` programmatically is that the XAML-Designer throws errors that it can't resolve the referenced resources (even if everything is ressolved at runtime). Is there any chance of setting the `ResourceDictionaries` programmatically and still let the XAML-Designer find the resources? I don't want to dig through hundreds of error messages to find the relevant ones. – croxy Apr 24 '17 at 12:39
  • I don't know. The XAML designer is not very useful at all in my opinion. I always disable it: http://blog.spinthemoose.com/2013/03/24/disable-the-xaml-designer-in-visual-studio/. It simply cannot handle all things that may happen at runtime and I wouldn't spend to much time of trying to fix design issues. It is doomed to fail anyway. Every serious WPF developer should learn XAML and a .NET programming language :) The designer are for designers. – mm8 Apr 24 '17 at 12:42
  • Okay thank you very much for the input. Until now I never considered deactivating the XAML designer because it was there since the beginning. I've never really needed it. I guess it was pure habit letting it activated. I guess I have to reconsider some life decisions ;). – croxy Apr 24 '17 at 12:51