0

我在解决 ResourceDictionaries 中的资源时遇到问题。

我决定将我相当大的 ResourceDictionary 重构为单独的字典文件,并组织到子文件夹中。

我在资源下有一个 ResourceLibrary.xaml:

<ResourceDictionary x:Class="MyProject.Resources.ResourceLibrary"
                xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
   <ResourceDictionary.MergedDictionaries>
     <!-- Colours -->
     <ResourceDictionary Source="Colors/ConnectedCellColor.xaml" />
     <!-- Brushes -->
     <ResourceDictionary Source="Brushes/ConnectorCellBrush.xaml" />
     <!-- Control Templates -->
     <ResourceDictionary Source="ControlTemplates/ConnectorCellTemplate.xaml" />
     <!-- Base Styles -->
     <ResourceDictionary Source="BaseStyles/ConnectorBaseStyle.xaml" />
   </ResourceDictionary.MergedDictionaries>
</ResourceDictionary>

该类的存在是有原因的,在后面的代码中,我可以添加 [Export(typeof (ResourceDictionary))] 以便 MEF 可以找到它。

我有一个观点:(简化)

<UserControl x:Class="MyProject.ConnectorCellView"
         Style="{StaticResource ConnectorBaseStyle}"
</UserControl>

连接器底座样式:

<ResourceDictionary>
   <Style x:Key="ConnectorBaseStyle" TargetType="UserControl">
      <Setter Property="Template" Value="{StaticResource ConnectorCellTemplate}" />
   </Style>
</ResourceDictionary>

该模板具有 StaticResources 来尝试获取画笔和颜色。

所有这些 StaticResources 将不再解析。

我认为这可能是一个订单问题,但由于这些资源包含在我的主程序的插件中,我使用 MEF 和 ImportMany 来获取所有导出的 ResourceDictionaries,并在我的 Caliburn.Micro 引导程序中:

  public void OnImportsSatisfied()
  {
     foreach (ResourceDictionary resourceDictionary in ResourceDictionaries)
     {
        Application.Resources.MergedDictionaries.Add(resourceDictionary);
     }
  }

(我在某处发现的巧妙技巧)

我实际上可以运行我的程序,当创建该视图时,它会在尝试设置样式时引发异常:

System.InvalidCastException
无法将“MS.Internal.NamedObject”类型的对象转换为 System.Windows.FrameworkTemplate 类型。

我发现与此相关的唯一信息与定义的订单资源有关,但是从我在 ResourceLibrary 中的订单来看,它应该可以工作。

抛出异常时,我可以检查 Application.Current.Resources.MergedDictionaries,并查看资源。

我尝试了各种在 ResourceLibrary 中指定 Source 的方法

<ResourceDictionary Source="/MyProject;component/Resources/BaseStyles/ConnectorBaseStyle.xaml" />

等,对找到它们没有影响。这些资源仅供插件代码使用。

似乎唯一可行的是将所有 StaticResources 更改为 DynamicResources

这对我来说没有意义,如果这是一个订单问题,为什么当它们都在同一个文件中时静态会起作用?

我的一些样式使用了 BasedOn,它们不适用于 DynamicResource。

你能帮我理解为什么会发生这种情况,以及如何让它发挥作用吗?

4

1 回答 1

1

这是一个排序问题,但与您的合并顺序无关 - 它与加载顺序有关。这基本上是加载 ResourceLibrary 字典时发生的情况:

  1. ConnectedCellColor 实例化
  2. ConnectedCellColor 加载到 ResourceLibrary
  3. ConnectorCellBrush 实例化
  4. ConnectorCellBrush 加载到 ResourceLibrary
  5. ConnectorCellTemplate 实例化
  6. ConnectorCellTemplate 加载到 ResourceLibrary
  7. ConnectorBaseStyle 实例化
  8. ConnectorBaseStyle 加载到 ResourceLibrary

这里的问题是,以前使用单个文件只有一个实例化步骤,现在您将其分解为多个步骤,每个步骤都是独立发生的。当实例化 ConnectorBaseStyle 时,ConnectorCellTemplate 已加载,但此时 ConnectorBaseStyle 不知道 ResourceLibrary 的内容。这DynamicResource不是问题,因为这些引用可以在第 8 步解决,但StaticResource需要在第 7 步立即解决。

最简单的解决方法是尽可能使用Dynamic。对于需要Static(例如BasedOn)的地方,您需要保证资源在实例化期间可用,例如,通过将 ConnectorCellTemplate 合并到 ConnectorBaseStyle 中,或者将所需的所有内容合并到对所有内容都可用的 App.xaml 中。当您获得更多文件并合并到多个位置时,这会使事情变得复杂且难以管理,但至少资源系统足够智能以识别重复项,因此在上述情况下,您仍然只能获得一个 ConnectorCellTemplate 实例,即使它正在两个地方合并。

于 2013-02-04T17:18:23.907 回答