【问题标题】:Can't share ResourceDictionary between different projects无法在不同项目之间共享 ResourceDictionary
【发布时间】:2020-08-23 13:05:50
【问题描述】:

我有几个 Windows 应用程序项目,它们的 app.xaml 文件中都有相同的复制粘贴 ResourceDictionary。我想删除此代码重复,将ResourceDictionary 放在项目中的一个文件中,并使用ResourceDictionary.Source 参数来引用它。

目前每个项目的 app.xaml 文件中都有这样的内容:

<ResourceDictionary.MergedDictionaries>
    <ResourceDictionary Source="/SomeProject;component/SomePath/First.xaml"/>
    <ResourceDictionary Source="/SomeProject;component/SomePath/Second.xaml"/>
    <ResourceDictionary Source="/SomeProject;component/SomePath/Third.xaml"/>
    ...
</ResourceDictionary.MergedDictionaries>

因此,我将所有内容放在名为 Common 的项目中的一个名为 Resources.xaml 的文件中(为了示例),并在 app.xaml 中将代码更改为:

<Application.Resources>
    <ResourceDictionary Source="pack://application:,,,/Common;component/Resources.xaml"/>
</Application.Resources>

当我在文件名上单击 F12 时,它会将我定向到预期的 Resources.xaml 文件,但是当我启动应用程序时出现异常:

System.Windows.Markup.XamlParseException: ''{DependencyProperty.UnsetValue}' 不是属性的有效值 '背景'。'

内部异常:InvalidOperationException: “{DependencyProperty.UnsetValue}”不是属性的有效值 “背景”。

我将 Resources.xaml 构建选项从“页面”更改为“资源”,但它没有改变任何东西。 我还查看了this question,似乎我必须将所有StaticResource 引用更改为DynamicResources,这对我来说不是一个真正可行的解决方案。

如何防止异常?有没有其他方法可以防止这种代码重复?

【问题讨论】:

  • 尝试手动获取 Res.xaml 中定义的每个 resdict,并将其在 App.xaml.cs 中加载到您的应用资源中,并检查是否适合您。

标签: c# .net wpf resourcedictionary


【解决方案1】:

您必须使用 MergedDictionaries 并使用 pack URI 方案来完全限定合并的资源。

“我有几个 Windows 应用程序项目,它们的 app.xaml 文件中都有相同的复制粘贴 ResourceDictionary。”

通常你创建一个单独的 WPF APP 项目并将其设置为启动项目。每个额外的项目都是类型库。这意味着它们不包含应用程序或框架入口点,这是一个派生自 Application 的类,通常是 App.xamlApp 中定义的部分类 App。 xaml.cs。 Visual Studio 为 WPF 自定义控件库WPF 用户控件库 等控件库提供项目模板。
WPF 应用程序仅包含一个活动的 App.xaml 文件。如果您需要引用启动程序集以外的程序集中的资源,您可以通过在相关资源文件中定义MergedDictionaries 来导入它们。

App.xaml

<Application.Resources>
  <ResourceDictionary.MergedDictionaries>
    <ResourceDictionary Source="pack://application:,,,/SomeProject;component/SomePath/First.xaml" />
    <ResourceDictionary Source="pack://application:,,,/SomeProject;component/SomePath/Second.xaml" />
    <ResourceDictionary Source="pack://application:,,,/SomeProject;component/SomePath/Third.xaml" />
    ...
  </ResourceDictionary.MergedDictionaries>
</Application.Resources>

如果可能,建议将所有相关和共享资源移至 App.xaml 字典。这消除了在 App.xaml 之外定义 MergedDictionaries 的需要,这可以提高性能。

还要确保MergedDictionaries 集合中合并的ResourceDictionary 项目的顺序以正确的顺序添加。


问题

请注意,XAML 解析器遵循某些查找规则。此外,StaticResource 查找不支持前向声明:所有引用的资源都必须在实际引用声明之前定义。
特别是在处理MergedDictionaries时,声明的顺序非常重要。

简而言之,静态资源查找在本地从当前元素的ResourceDictionary 开始。如果在其范围内未找到资源键,XAML 解析器将向上遍历逻辑树以检查逻辑父级的字典,直到它到达根元素,例如Window。在根元素之后,解析器检查应用程序的资源字典,然后是主题字典。

如果解析器遇到MergedDictionaries(在首先检查当前ResourceDictionary 之后),它将迭代合并的ResourceDictionary 集合以倒序从下到上或从最后到第一 .

由于 XAML 解析器不支持前向声明,因此合并资源的顺序非常重要。
采取以下MergedDictionaries 收藏:

<ResourceDictionary.MergedDictionaries>
  <ResourceDictionary Source="/SomePath/First.xaml" />
  <ResourceDictionary Source="/SomePath/Second.xaml" />
  <ResourceDictionary Source="/SomePath/Third.xaml" />
</ResourceDictionary.MergedDictionaries>

现在考虑以下情况:您有一个元素,例如静态引用 ControlTemplateButton,它在 Third.xaml 的合并字典内的父元素字典中定义。但是这个模板还包含一个元素,它静态引用 First.xaml 中定义的Style

如果在 Third.xaml 中声明的元素或资源需要从 First.xaml 静态引用资源,则解析器无法解析这些资源:解析器搜索对于ControlTemplate 并到达父母的ResourceDictionary。这本字典不包含引用,而是一个MergedDictioanaries 集合。所以它开始以相反的顺序遍历这个集合,从最后到第一个或从下到上:它从 Third.xaml 开始并成功找到引用的ControlTemplate

为了实例化这个模板,解析器必须解析所有模板资源。在这个模板中,解析器找到了一个需要Style 的元素,但是这个Style 在任何以前合并的ResourceDictionary 中都没有找到。它在 First.xamlResourceDictionary 中定义,尚未访问(前向声明)。因此无法解析此资源。

解决方案

要解决此问题,您可以将合并的字典按正确的顺序排列:

<!-- Collection is iterated in reverse order -->
<ResourceDictionary.MergedDictionaries>
  <ResourceDictionary Source="/SomePath/Third.xaml" />
  <ResourceDictionary Source="/SomePath/Second.xaml" />
  <ResourceDictionary Source="/SomePath/First.xaml" />
</ResourceDictionary.MergedDictionaries>

或者使用DynamicResource 标记将静态引用替换为动态引用。

DynamicResource 标记指示 XAML 解析器在第一次查找过程中创建一个临时表达式(第一次查找过程是前面描述的,并在编译时解析静态引用)。在这第一遍之后,在运行时进行第二次查找。解析器再次遍历树以执行先前在第一次查找过程中由 DynamicResource 标记创建的临时表达式。

因此,当您无法在声明之前提供资源的定义时,您必须使用DynamicResource 查找。

【讨论】:

    猜你喜欢
    • 2018-03-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-07
    • 1970-01-01
    相关资源
    最近更新 更多