在运行时合并WPF ResourceDictionary

时间:2017-06-03 18:53:21

标签: c# wpf xaml resourcedictionary

我有一个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目录中。

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

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时会抛出异常。消息是“无法找到资源'defaultresources.xaml'”。

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

如果有一种不同的方法将可选资源程序集合并到WPF项目中,我很乐意听到它。我也会理解我的具体问题的答案:)

更新

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

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

我收到设计时错误“找到资源字典时出错...”

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

  

Olbert.JumpForJoy.WPF.DefaultResources.xaml

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

1 个答案:

答案 0 :(得分:1)

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

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

的博客上更全面地记录了这一点