【问题标题】:Merging WPF ResourceDictionary at Runtime在运行时合并 WPF ResourceDictionary
【发布时间】:2017-11-04 23:03:37
【问题描述】:

我有一个 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 时是否需要以某种方式指定该命名空间。

【问题讨论】:

  • 直接在&lt;Application.Resources&gt;中合并外部资源在App.xaml中是否会出现错误?

标签: c# wpf xaml resourcedictionary


【解决方案1】:

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

我已经在我的博客http://jumpforjoysoftware.com/2017/06/the-pain-of-shared-wpf-resources/ 上详细记录了这一点

【讨论】:

  • 我很抱歉,@Graviton:由于转移到 WordPress 中的新 Gutenberg 编辑器,我的一些帖子被破坏了,包括这里引用的那个。不幸的是,我没有这篇文章的备份或替代来源。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-09
  • 1970-01-01
  • 2012-01-19
  • 1970-01-01
相关资源
最近更新 更多