WPF中的StaticResource有效,DynamicResource无效。

11

我已经尝试了一整天,但无济于事,想要创建一堆笔刷并在自定义控件中使用DynamicResource。我的步骤如下:

  • 创建包含样式的主题generic.xaml(可行)
  • 添加一个字典,将其与generic.xaml合并,包含应用程序使用的笔刷(可行)
  • 让笔刷具有ComponentResourceKey键(可行)
  • 将控件作为静态资源使用笔刷(可行)
  • 将控件作为动态资源使用笔刷(不可行,资源跟踪源也显示如此:System.Windows.ResourceDictionary Warning: 9 : Resource not found; )
  • 在App.Resources中动态添加具有相同键的笔刷(对于动态资源有效,它更改颜色,对于静态资源无效,如预期)

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

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

有人可以帮帮我吗?:(

3个回答

7
这里有一个区别,StaticResource在加载时加载,这意味着您使用的资源键必须在使用之前被词法定义。
因此,在自定义控件的情况下,静态资源必须仅在相同的generic.xaml文件中的控件定义之上定义。因此,如果您将画笔放在不同的xaml中,则在使用静态资源时肯定无法工作。
这就是为什么除非以某种导入形式在同一文件中编译时包含类型为xaml的其他资源,否则无法在文件中使用静态资源的原因。这简单地意味着文件/组件/控件的实际xaml应该以某种方式包含您使用的静态资源的实际引用。
现在我对为什么DynamicResource不起作用有疑问,可能是因为DynamicResource只会查找应用程序(使用控件的位置)ResourceDictionary而不是generic.xaml。
我不是100%确定,但我认为如果您定义了自定义控件并且使用DynamicResource,则您的资源必须位于Application的Resource Dictionary或您的控件的ResourceDictionary的父容器中,但不能位于generic.xaml中。
因为DynamicResource只会在控件运行时的逻辑树中查找键,所以它可能无法找到在generic.xaml中的资源,除非将generic.xaml明确添加到Application.Resources中。
总结: StaticResource必须在编译时在同一文件中以词法方式可用,资源将在Application.Resources字典中可用,在逻辑树中仍然可以找到,但仅在同一dll或相同的generic.xaml中进行编译时。 DynamicResource必须在运行时在Application.Resources和控件的逻辑树中搜索。
有关更多参考,请查看资源概述

谢谢你的回答,即使我感觉它并不好 :), 但问题是这样的:为了访问在主题中定义的资源,必须使用ComponentResourceKey。简化问题,我可以使用另一个程序集中的类型定义一个使用ComponentResourceKey定义的主题资源,然后我无法使用FindResource找到该资源。如果使用与主题文件相同的程序集中的类型,则可以找到该资源。 - Siderite
我觉得这与某种汇编加载顺序有关,但如果您正在使用该程序集中的类型查找资源,那么如何不加载程序集呢? - Siderite
如果资源x在generic.xaml中,即使它已经被加载并存在于内存中,动态资源也无法找到它,它只能在其自己的逻辑父树的资源字典中找到。动态资源加载使用FindResource方法,但StaticResource不使用FindResource方法,而是在编译时设置资源引用。 - Akash Kava
好的,我理解了。问题是为什么FindResource失败了?我的意思是,更改组件资源类型的类型会使其失败或成功。这是为什么呢? - Siderite
@AkashKava 无意冒犯,但是你之前写了一大段文字,实际上你只是想说"我不知道"。 - M.Stramm
重要提示:DynamicResources必须独占地合并到Application.Current.Resources中,任何其他逻辑树控件(例如Window)中的资源字典似乎都无法工作。此外,动态资源需要进行合并而不是添加。 - wondra

7
最终解决了问题。原来,将组件资源键的类型放在另一个程序集中导致了整个问题。让我总结一下:
  • 有一个资源类作为静态属性持有ComponentResourceKeys。构造函数中使用的类型是该类的类型。这在Resources程序集中。
  • 有一个自定义控件的主题在另一个程序集Controls中,它使用资源类的属性作为键定义了一些画刷:{x:Static Namespace:ResourceClass.ResourceKeyProperty}
  • 在同一个主题中,控件的模板将画刷作为动态资源使用:{DynamicResource {x:Static Namespace:ResourceClass.ResourceKeyProperty}}
  • 还有一个应用程序使用这些控件并在应用程序资源中动态添加自定义画刷。这些画刷与主题中的画刷具有相同的键。

最终结果是:

  • 控件最初不使用画刷
  • 控件使用添加到应用程序资源中的画刷
  • 如果在主题中使用StaticResource,则控件最初使用画刷,但忽略应用程序资源

解决此问题的方法似乎是将资源类移动到控件库中。

由于我仍然不知道为什么会发生这种情况,因此即使稍微改变了一下,这个问题仍然存在:为什么第一种情况不起作用?


2

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

因此,我将描述不起作用的重现设置,而不是描述解决方案。

解决方案

目标框架:4.6

项目

  • Controls
    • references
      • Resources
    • files
      • Theme.xaml
  • Resources
    • files
      • Keys.cs
  • WpfApplication
    • references
      • Controls
      • Resources
    • files
      • 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>

对于懒人,这里有一张截图:

enter image description here


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接