您必须使用 MergedDictionaries 并使用 pack URI 方案来完全限定合并的资源。
“我有几个 Windows 应用程序项目,它们的 app.xaml 文件中都有相同的复制粘贴 ResourceDictionary。”
通常你创建一个单独的 WPF APP 项目并将其设置为启动项目。每个额外的项目都是类型库。这意味着它们不包含应用程序或框架入口点,这是一个派生自 Application 的类,通常是 App.xaml 和 App 中定义的部分类 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>
现在考虑以下情况:您有一个元素,例如静态引用 ControlTemplate 的 Button,它在 Third.xaml 的合并字典内的父元素字典中定义。但是这个模板还包含一个元素,它静态引用 First.xaml 中定义的Style。
如果在 Third.xaml 中声明的元素或资源需要从 First.xaml 静态引用资源,则解析器无法解析这些资源:解析器搜索对于ControlTemplate 并到达父母的ResourceDictionary。这本字典不包含引用,而是一个MergedDictioanaries 集合。所以它开始以相反的顺序遍历这个集合,从最后到第一个或从下到上:它从 Third.xaml 开始并成功找到引用的ControlTemplate。
为了实例化这个模板,解析器必须解析所有模板资源。在这个模板中,解析器找到了一个需要Style 的元素,但是这个Style 在任何以前合并的ResourceDictionary 中都没有找到。它在 First.xaml 的ResourceDictionary 中定义,尚未访问(前向声明)。因此无法解析此资源。
解决方案
要解决此问题,您可以将合并的字典按正确的顺序排列:
<!-- 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 查找。