资源无法从ResourceDictionaries解析

时间:2013-02-04 10:54:17

标签: wpf xaml resourcedictionary

我在从ResourceDictionaries解析资源时遇到问题。

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

我在Resources:

下有一个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>

ConnectorBaseStyle:

<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。

你能帮助我理解为什么会这样,以及如何让它发挥作用?

1 个答案:

答案 0 :(得分:1)

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

  1. ConnectedCellColor实例化
  2. ConnectedCellColor加载到ResourceLibrary
  3. ConnectorCellBrush实例化
  4. ConnectorCellBrush加载到ResourceLibrary
  5. ConnectorCellTemplate实例化
  6. ConnectorCellTemplate加载到ResourceLibrary
  7. ConnectorBaseStyle实例化
  8. ConnectorBaseStyle加载到ResourceLibrary
  9. 这里的问题是,在您使用单个文件之前,您只有一个实例化步骤,现在您可以将其分解为多个步骤,每个步骤都是独立完成的。实例化ConnectorBaseStyle时,已加载ConnectorCellTemplate,但此时ConnectorBaseStyle不知道ResourceLibrary的内容。使用DynamicResource这不是问题,因为这些引用只能在步骤8解决,但StaticResource需要在步骤7立即解决。

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

相关问题