What you request is a component of the functions necessary to ensure true skinning in the application. Getting resources from a separate assembly involves reading compiled XAML or BAML from another assembly. Here is the method that I use in the skin library to extract BAML from the assembly:
//Relevant Namespaces: //using System.Windows.Baml2006; //using System.Xaml; public static List<Stream> GetBamlStreams(AssemblyName skinAssemblyName) { List<Stream> bamlStreams = new List<Stream>(); Assembly skinAssembly = Assembly.Load(skinAssemblyName); string[] resourceDictionaries = skinAssembly.GetManifestResourceNames(); foreach (string resourceName in resourceDictionaries) { ManifestResourceInfo info = skinAssembly.GetManifestResourceInfo(resourceName); if (info.ResourceLocation != ResourceLocation.ContainedInAnotherAssembly) { Stream resourceStream = skinAssembly.GetManifestResourceStream(resourceName); using (ResourceReader reader = new ResourceReader(resourceStream)) { foreach (DictionaryEntry entry in reader) { //TODO: Figure out if this is a ResourceDictionary I care about //Key will be name of the RD (BrushResources.baml, in your case) if (IsRelevantResource(entry)) { bamlStreams.Add(entry.Value as Stream); } } } } } return bamlStreams; }
Then, to convert BAML to specific resources, you do the following:
//If .NET 3.5, need this initialization: //Type xamlType = typeof(System.Windows.Markup.XamlReader); //LoadBamlMethod = xamlType.GetMethod(LOAD_BAML_METHOD, BindingFlags.NonPublic | BindingFlags.Static); public static T LoadBaml<T>(Stream stream) { //For .net 3.5: //ParserContext parserContext = new ParserContext(); //object[] parameters = new object[] { stream, parserContext, null, false }; //object bamlRoot = LoadBamlMethod.Invoke(null, parameters); //return (T)bamlRoot; //For .net 4.0 var reader = new Baml2006Reader(stream); var writer = new XamlObjectWriter(reader.SchemaContext); while (reader.Read()) writer.WriteNode(reader); return (T)writer.Result; }
And in order to combine resources from another assembly into the current assembly:
private void LoadResources() { List<Stream> bamlStreams = GetBamlStreams(FullName); foreach (Stream stream in bamlStreams) { ResourceDictionary rd = LoadBaml<ResourceDictionary>(stream); Application.Current.Resources.MergedDictionaries.Add(rd) } }
In this example, this work is very versatile for trimming, but you can optimize it to achieve your specific goal, if necessary. You can see the skinning library that uses this method here on github , with a few examples to demonstrate.
source share