在运行时合并 WPF ResourceDictionary

Merging WPF ResourceDictionary at Runtime

我有一个 WPF 用户控件,它定义了一些我希望能够在运行时使用资源程序集中包含的自定义样式和图像覆盖的默认样式和图像。

样式和图像包含在名为 Olbert.JumpForJoy.DefaultResources 的程序集中名为 DefaultResources.xaml 的 ResourceDictionary 中:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    x:Name="J4JResources">

    <BitmapImage x:Key="J4JMessageBoxImage" UriSource="assets/j4jmsgbox.png" />
    <BitmapImage x:Key="J4JWizardImage" UriSource="assets/j4jtransparent.png" />
    <Color x:Key="J4JButton0Color">#bb911e</Color>
    <Color x:Key="J4JButton1Color">#252315</Color>
    <Color x:Key="J4JButton2Color">#bc513e</Color>
    <Color x:Key="J4JButtonHighlightColor">Orange</Color>

</ResourceDictionary>

为了将此提供给应用程序,我将资源项目编译时创建的 nuget 包添加到要使用自定义资源的应用程序中。我已经确认 dll 已添加到目标 bin 目录中。

我尝试在 App.xaml.cs 文件中的 OnStartup() 方法中加载自定义资源程序集:

public partial class App : Application
{
    public const string ResourceDll = "Olbert.JumpForJoy.DefaultResources";

    protected override void OnStartup( StartupEventArgs e )
    {
        try
        {
            var resDllPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $"{ResourceDll}.dll");

            if (File.Exists(resDllPath))
            {
                var resAssembly = Assembly.LoadFile(resDllPath);
                var uriText = $"pack://application:,,,/{resAssembly.GetName().Name};component/DefaultResources.xaml";

                ResourceDictionary j4jRD = new ResourceDictionary {
                        Source = new Uri(uriText)
                    };

                Resources.MergedDictionaries.Add(j4jRD);
            }
        }
        catch (Exception ex)
        {
        }
    }
}

但是在创建 ResourceDictionary 时抛出异常。消息是 "Cannot locate resource 'defaultresources.xaml'".

我已经尝试对 uri 定义进行很多调整来解决这个问题,none 其中一些已经奏效。资源程序集是版本化的,但无论我是否在 uri 定义中包含特定版本,我都会得到相同的错误。

如果有其他方法可以将可选资源程序集合并到 WPF 项目中,我很想听听。也将不胜感激对我的具体问题的回答:)

更新

如果我尝试通过 app.xaml 执行此操作:

<ResourceDictionary.MergedDictionaries>
    <ResourceDictionary Source="pack://application:,,,/Olbert.JumpForJoy.DefaultResources;component/DefaultResources.xaml" />
    <ResourceDictionary Source="NotifyIconResources.xaml"/>
</ResourceDictionary.MergedDictionaries>

我收到设计时错误"An error occurred while finding the resource dictionary..."

在我原来的方法中调用 resAssembly.GetManifestResourceNames() 表明资源确实存在于自定义程序集中。但是它们出现 "under" 程序集的默认命名空间:

Olbert.JumpForJoy.WPF.DefaultResources.xaml

这让我想知道在定义 Uri 时是否需要以某种方式指定该命名空间。

为了其他人在这个问题上苦苦挣扎,这是我发现的解决方案:问题是外部资源程序集的默认命名空间 必须 与名称相同该程序集的 DLL。如果名称不同,则包 Uri 语法将失败。

我在我的博客 http://jumpforjoysoftware.com/2017/06/the-pain-of-shared-wpf-resources/

上对此进行了更全面的记录