【问题标题】:Instantiate ResourceDictionary xaml from other Assembly从其他程序集实例化 ResourceDictionary xaml
【发布时间】:2013-03-21 13:21:04
【问题描述】:

我在 WPF 类库中定义了一个资源字典,其中包含颜色和画笔,称为 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>

我想在另一个程序集中的代码中使用一些画笔,它引用了这个库项目。如何获取ResourceDictionary的Instance呢?

【问题讨论】:

    标签: c# wpf xaml resourcedictionary


    【解决方案1】:

    您要问的是在应用程序中提供真正换肤所需的功能组件。从单独的程序集中获取资源涉及从另一个程序集中读取已编译的 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 的蒙皮库,并提供了一些示例进行演示。

    【讨论】:

    • 非常感谢,正是我需要的。
    • 每个 .baml 条目都不能直接转换为“ResourceDictionary”。不应该先检查一下吗?
    【解决方案2】:

    您不必将 ResourceDictionary 放在“App.xaml”中。如果你有一个 UserControl 或 Window,你可以链接到你的 ResourceDictionary。

    <UserControl.Resources>
     <ResourceDictionary>
      <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary Source="/MyProjectName;component/BrushResources.xaml" />
      </ResourceDictionary.MergedDictionaries>
     </ResourceDictionary>
    </UserContro.Resources>
    

    【讨论】:

    • 我知道,但我需要通过代码访问资源字典中的画笔,不涉及 xaml。
    【解决方案3】:

    为什么不在您的其他程序集中使用 MergedDictionaries?

     <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary Source="pack://application:,,,/BrushesLib;Component/BrushResources.xaml" />
    </ResourceDictionary.MergedDictionaries>
    

    【讨论】:

    • 因为另一个程序集也是一个类库,因此没有 App.xaml。我需要代码中的对象。
    【解决方案4】:

    如果您知道另一个 assembly 结构,请使用以下代码: XAML 解决方案

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

    输出:如果我们想使用ResourceDictionaryRD1.xaml的项目WpfControlLibrary1StackOverflowApp项目。

    项目结构:

    资源字典

    代码输出:

    c#解决方案:

    使用this链接。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多