WPF StaticResource 有效,DynamicResource 无效

发布于 2024-09-15 18:01:49 字数 825 浏览 1 评论 0原文

我已经尝试了一天,但没有成功,在主题中创建一堆画笔,然后在自定义控件中将它们与 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 标记中,它仍然不起作用。

有人可以帮我吗? :(

I have been trying for a day now, to no avail, to create a bunch of brushes in the theme then using them with DynamicResource in a custom control. What I did is this:

  • create the theme generic.xaml which contains styles (works)
  • add a dictionary to merge in generic.xaml to contain brushes used in the application (works)
  • make brushes have ComponentResourceKey keys (works)
  • make control use brushes as static resource (works)
  • make control use brushes as dynamic resource (DOESN'T WORK, the resource trace source says as much: System.Windows.ResourceDictionary Warning: 9 : Resource not found; )
  • add in App.Resources dynamically a brush with the same key (works with dynamic resource, it changes the colors, doesn't work with static resource, as expected)

So my problem is that I can't find any way to define the default values in the theme so that I can change them programatically in the application. How can StaticResource find the brush and DynamicResource not?!

I must add that I've created a static class holding the component resource keys as properties that I then use in the xaml as {x:Static UI:ResourceScheme.ControlBackgroundKey} for example. My problem seems similar to this one: ComponentResourceKey as DynamicResource problem only that if I replace the static property keys to the XAML markup for component resource key, it still doesn't work.

Can someone please help me out here? :(

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

骄兵必败 2024-09-22 18:01:49

区别在于,

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

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

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

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

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

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

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

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

如需更多参考,请查看资源概述

Here is the difference,

StaticResource loads at time of loading, this means that the resource key that you are using, must be lexically defined before the usage.

So, static resource in case of custom control must be defined only above the control definition in the same generic.xaml file. So if you put your brushes in different xaml, it will certainly not work in case of static resource.

This is the reason, unless the other resources of type xaml is included in the form of some sort of import at a time of complile in same file, you can not use static resource in the file. It simply means that the file/component/control's actual xaml some how should contain actual reference of static resource you use.

Now I have my doubt of why DynamicResource will not work, that is because probably DynamicResource will only look in the Application's (where the control is use) ResourceDictionary but not generic.xaml.

I am not 100% sure but I feel if you define a custom control and if you use DynamicResource then your resources has to be in the Application's Resource Dictionary or the parent container of your control's resource dictionary, but it can not be in generic.xaml.

Because DynamicResource will only look up for keys in the logical tree of control's runtime and thats why it may not find resources that are in generic.xaml unless generic.xaml is explicitly added in Application.Resources.

Summary:
StaticResource must be available lexically before in the same file at compile time, resources will be available in Application.Resources dictionary, it still can find in logical tree but at a compile time only in the same dll or same generic.xaml.

DynamicResource must will be searched in Application.Resources and in the logical tree of the control at runtime.

For more reference, please check Resources Overview

彻夜缠绵 2024-09-22 18:01:49

终于修好了。看来整个问题是由另一个程序集中的组件资源键的类型引起的。让我总结一下:

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

最终结果是:

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

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

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

Finally fixed it. It appears that having the type for the component resource key in another assembly caused the whole issue. Let me summarize:

  • there is a resource class that holds the ComponentResourceKeys as static properties. The type used in the constructor of the resource keys is the type of this class. This is in the Resources assembly.
  • there is a theme for the custom controls in another assembly, the Controls assembly, that defines some brushes using as key the properties of the resource class: {x:Static Namespace:ResourceClass.ResourceKeyProperty}
  • in the same theme, templates for controls use the brushes as dynamic resources: {DynamicResource {x:Static Namespace:ResourceClass.ResourceKeyProperty}}
  • there is also an application that uses these controls and that dynamically adds custom brushes in the application resources. These brushes have the same keys as the ones in the theme.

The end result for this is:

  • the controls do not use the brushes initially
  • the controls do use the brushes added in the application resources
  • the controls use the brushes initially if StaticResource is used in the theme, but then the application resources are ignored

The solution for this seems to be to move the resources class in the controls library.

As I still do not know why this is happening, this question remains open, even if slightly changed: why doesn't it work in the first scenario?

天冷不及心凉 2024-09-22 18:01:49

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

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

解决方案

目标框架:4.6

项目

  • 控制
    • 参考文献
      • 资源
    • 文件
      • 主题.xaml
  • 资源
    • 文件
      • Keys.cs
  • WpfApplication
    • 参考文献
      • 控件
      • 资源
    • 文件
      • 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>

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

在此处输入图像描述

I tried to reproduce your problem to test out a few theories of why it doesn't work, however I couldn't reproduce the problem. The setup appears to work.

So instead of describing a solution I will describe the non-working repro setup.

The solution

Target framework: 4.6

Projects

  • Controls
    • references
      • Resources
    • files
      • Theme.xaml
  • Resources
    • files
      • Keys.cs
  • WpfApplication
    • references
      • Controls
      • Resources
    • files
      • MainWindow.xaml

File contents

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>

And for the lazy people, here's a screenshot:

enter image description here

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文