【问题标题】:WPF StaticResource works, DynamicResource doesn'tWPF StaticResource 有效,DynamicResource 无效
【发布时间】:2015-12-20 23:11:55
【问题描述】:

我已经尝试了一天,但无济于事,在主题中创建一堆画笔,然后在自定义控件中将它们与 DynamicResource 一起使用。我做的是这样的:

  • 创建包含样式(作品)的主题 generic.xaml
  • 在 generic.xaml 中添加要合并的字典,以包含应用程序中使用的画笔(作品)
  • 使画笔具有 ComponentResourceKey 键(有效)
  • 使控件使用画笔作为静态资源(有效)
  • 使控件使用画笔作为动态资源(不工作,资源跟踪源说明:System.Windows.ResourceDictionary 警告:9:找不到资源;)
  • 在 App.Resources 中动态添加具有相同键的画笔(适用于动态资源,它会更改颜色,不适用于静态资源,正如预期的那样)

所以我的问题是我找不到任何方法来定义主题中的默认值,以便我可以在应用程序中以编程方式更改它们。 StaticResource怎么能找到画笔而DynamicResource找不到?!

我必须补充一点,我创建了一个静态类,将组件资源键作为属性保存,然后在 xaml 中用作 {x:Static UI:ResourceScheme.ControlBackgroundKey}。我的问题似乎与这个类似:ComponentResourceKey as DynamicResource problem 只是如果我将静态属性键替换为组件资源键的 XAML 标记,它仍然不起作用。

有人可以帮我吗? :(

【问题讨论】:

    标签: wpf xaml themes dynamicresource componentresourcekey


    【解决方案1】:

    这就是区别,

    StaticResource 在加载时加载,这意味着您正在使用的资源键必须在使用之前进行词法定义。

    因此,在自定义控件的情况下,静态资源只能在同一个 generic.xaml 文件中的控件定义之上定义。所以如果你把你的画笔放在不同的xaml中,它肯定不会在静态资源的情况下工作。

    这就是原因,除非 xaml 类型的其他资源在编译时以某种导入的形式包含在同一文件中,否则您不能在文件中使用静态资源。它只是意味着文件/组件/控件的实际 xaml 应该包含您使用的静态资源的实际引用。

    现在我怀疑为什么 DynamicResource 不起作用,那是因为 DynamicResource 可能只会查看应用程序的(使用控件的地方)ResourceDictionary 而不是 generic.xaml。

    我不是 100% 肯定,但我觉得如果你定义一个自定义控件并且如果你使用 DynamicResource 那么你的资源必须在应用程序的资源字典或控件资源字典的父容器中,但它不能在generic.xaml。

    因为 DynamicResource 只会在控件运行时的逻辑树中查找键,这就是为什么它可能无法找到 generic.xaml 中的资源,除非在 Application.Resources 中显式添加 generic.xaml。

    总结: StaticResource 必须在编译时在同一个文件中之前在词法上可用,资源将在 Application.Resources 字典中可用,它仍然可以在逻辑树中找到,但在编译时只能在同一个 dll 或同一个 generic.xaml 中。

    DynamicResource 必须在运行时在 Application.Resources 和控件的逻辑树中进行搜索。

    更多参考,请查看Resources Overview

    【讨论】:

    • 感谢您的回答,即使我不觉得这有什么好处:),但问题是:为了访问主题中定义的资源,必须使用 ComponentResourceKey。简化问题,我在主题中定义了一个资源,其中一个 ComponentResourceKey 使用另一个程序集中的类型定义,然后我无法使用 FindResource 找到该资源。使用与主题文件相同的程序集中的类型,我可以找到资源。
    • 我觉得这与某种程序集加载顺序有关,但是如果您尝试使用该程序集中的类型查找资源,您怎么能不加载程序集呢?
    • 如果资源x在generic.xaml中,即使加载到内存中,动态资源也找不到,只能在自己的逻辑父树的资源字典中找到。动态资源加载使用 FindResource,但 StaticResource 不使用 FindResource 方法,而是在编译时设置资源引用。
    • 好的,我明白了。问题是 FindResource 为什么会失败?我的意思是,更改组件资源类型的类型使其要么失败要么成功。这是为什么呢?
    • @AkashKava 无意冒犯,但实际上你想说“我不知道”时却写了一堵文字墙
    【解决方案2】:

    终于修好了。似乎在另一个程序集中拥有组件资源键的类型会导致整个问题。让我总结一下:

    • 有一个资源类将 ComponentResourceKeys 保存为静态属性。资源键的构造函数中使用的类型就是这个类的类型。这是在资源程序集中。
    • 另一个程序集中的自定义控件有一个主题,即控件程序集,它使用资源类的属性作为键定义了一些画笔:{x:Static Namespace:ResourceClass.ResourceKeyProperty}
    • 在同一主题中,控件模板使用画笔作为动态资源:{DynamicResource {x:Static Namespace:ResourceClass.ResourceKeyProperty}}
    • 还有一个应用程序使用这些控件并在应用程序资源中动态添加自定义画笔。这些画笔的键与主题中的相同。

    这样做的最终结果是:

    • 控件最初不使用画笔
    • 控件确实使用应用程序资源中添加的画笔
    • 如果在主题中使用 StaticResource,则控件最初使用画笔,但随后会忽略应用程序资源

    对此的解决方案似乎是在控件库中移动资源类。

    由于我仍然不知道为什么会发生这种情况,这个问题仍然悬而未决,即使略有改变:为什么它在第一种情况下不起作用?

    【讨论】:

      【解决方案3】:

      我试图重现您的问题以测试一些关于它为什么不起作用的理论,但是我无法重现该问题。设置似乎有效。

      因此,我不会描述解决方案,而是描述无法正常工作的重现设置。

      解决办法

      目标框架:4.6

      项目

      • 控件
        • 参考资料
          • 资源
        • 文件
          • Theme.xaml
      • 资源
        • 文件
          • Keys.cs
      • Wpf 应用程序
        • 参考资料
          • 控件
          • 资源
        • 文件
          • MainWindow.xaml

      文件内容

      Theme.xaml

      <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                          xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                          xmlns:r="clr-namespace:Resources;assembly=Resources">
          <Color x:Key="{x:Static r:Keys.PrettyColor}">Red</Color>
          <SolidColorBrush x:Key="{x:Static r:Keys.PrettyBrush}" 
                           Color="{DynamicResource {x:Static r:Keys.PrettyColor}}" />
      </ResourceDictionary>
      

      Keys.cs

      namespace Resources {
          using System.Windows;
      
          public static class Keys {
              public static readonly ComponentResourceKey PrettyBrush =
                  new ComponentResourceKey(typeof(Keys), Ids.PrettyBrush);
      
              public static readonly ComponentResourceKey PrettyColor =
                  new ComponentResourceKey(typeof(Keys), Ids.PrettyColor);
          }
      
          public static class Ids {
              public const string PrettyBrush = "PrettyBrush";
              public const string PrettyColor = "PrettyColor";
          }
      }
      

      MainWindow.xaml

      <Window x:Class="WpfApplication1.MainWindow"
              xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
              xmlns:resources="clr-namespace:Resources;assembly=Resources"
              Title="MainWindow" Height="350" Width="525">
          <Window.Resources>
              <ResourceDictionary>
                  <ResourceDictionary.MergedDictionaries>
                      <ResourceDictionary Source="/Controls;component/Theme.xaml" />
                  </ResourceDictionary.MergedDictionaries>
                  <Color x:Key="{x:Static resources:Keys.PrettyColor}">Blue</Color>
              </ResourceDictionary>
          </Window.Resources>
          <Border Background="{DynamicResource {x:Static resources:Keys.PrettyBrush}}" />
      </Window>
      

      对于懒惰的人,这里有一个截图:

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-09-17
        • 2010-12-24
        • 1970-01-01
        • 2012-01-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多