我在WPF类库中定义了一个Reource字典,其中包含颜色和画笔,称为BrushResources.xaml。

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Lots of Colors and Brushes here>
</ResourceDictionary>

我想在另一个程序集的代码中使用某些Brushes,该程序集引用了此库项目。如何获得它的ResourceDictionary的实例?

最佳答案

您要问的是在应用程序中提供真实外观所需的功能的组成部分。从单独的程序集中获取资源涉及从另一个程序集中读取已编译的XAML或BAML。这是我在外观库中使用的从程序集中检索BAML的方法:

//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;
}

然后,要将BAML转换为特定资源,请执行以下操作:
//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;
}

为了将资源从另一个程序集中合并到当前程序集中,请执行以下操作:
private void LoadResources()
{
    List<Stream> bamlStreams = GetBamlStreams(FullName);
    foreach (Stream stream in bamlStreams)
    {
        ResourceDictionary rd = LoadBaml<ResourceDictionary>(stream);
        Application.Current.Resources.MergedDictionaries.Add(rd)
    }
}

此示例出于蒙皮的目的以非常通用的方式进行工作,但是您可以根据需要简化此过程以实现您的特定目标。您可以看到使用此方法here on github的外观库,并带有一些示例进行演示。

10-04 14:11