如何使用 DynamicResource 更新 SolidColorBrush 颜色?

Dan*_*lba 5 c# wpf colors

我正在尝试动态更改画笔的颜色。我写了一个非常简单的例子,但我不明白为什么它不起作用。

我在我的应用程序的 ResourceDictionary 中定义了一个前景色和一个使用该颜色作为 DynamicResource 的前景画笔:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <Color x:Key="Foreground">#FF0000</Color>
    <SolidColorBrush x:Key="ForegroundBrush" Color="{DynamicResource Foreground}" />

</ResourceDictionary>
Run Code Online (Sandbox Code Playgroud)

然后,在我的 Window.xaml 中,我使用画笔设置文本块前景:

<Window x:Class="DictionaryColorTests.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <StackPanel>
            <TextBlock Name="mTextBlock"  Foreground="{DynamicResource ForegroundBrush}">This is just a text block</TextBlock>
            <Button Name="Button1" Click="Button1_Click">Change color</Button>
        </StackPanel>
    </Grid>
</Window>
Run Code Online (Sandbox Code Playgroud)

最后在我的代码后面,我改变了颜色:

private void Button1_Click(object sender, RoutedEventArgs e)
{
    Application.Current.Resources["Foreground"] = Colors.Green;
}
Run Code Online (Sandbox Code Playgroud)

不幸的是,画笔颜色没有更新。有人可以解释一下为什么吗?

注意:我知道,如果直接更改画笔的颜色,效果很好,但我试图理解为什么使用颜色作为动态​​资源的 SolidColorBrush 在颜色更改时不会更新其颜色。


更新:使用一种可以按预期工作的样式

如果我对文本块使用样式,只需更新颜色,它就可以正常工作并且画笔会采用正确的颜色。直接使用画笔和使用样式有什么区别?

<Style TargetType="TextBlock" x:Key="TextBlockStyle">
    <Setter Property="Foreground" Value="{StaticResource ForegroundBrush}" />
</Style>
Run Code Online (Sandbox Code Playgroud)

Pet*_*iho 6

如果没有一个好的最小、完整和可验证的代码示例来可靠地重现您的问题,就不可能确定问题是什么。但基本问题似乎是您试图DynamicResource以不受支持的方式使用。

\n\n

文档中:

\n\n
\n

动态资源引用有一些显着的限制。至少必须满足以下条件之一:

\n\n

\xe2\x80\xa2 所设置的属性必须是 FrameworkElement 或 FrameworkContentElement 上的属性。该属性必须由 DependencyProperty 支持。

\n\n

\xe2\x80\xa2该引用适用于 StyleSetter 中的值。

\n\n

\xe2\x80\xa2要设置的属性必须是 Freezable 上的属性,该属性作为 FrameworkElement 或 FrameworkContentElement 属性的值或 Setter 值提供。

\n\n

由于要设置的属性必须是 DependencyProperty 或 Freezable 属性,因此大多数属性更改都可以传播到 UI,因为属性更改(更改后的动态资源值)会被属性系统确认。大多数控件都包含逻辑,如果 DependencyProperty 发生更改并且该属性可能会影响布局,则该逻辑将强制控件采用另一种布局。但是,并非所有具有 DynamicResource 标记扩展作为其值的属性都保证以在 UI 中实时更新的方式提供值 [强调我的]。该功能仍然可能会根据属性、拥有该属性的类型甚至应用程序的逻辑结构而有所不同。

\n
\n\n

您正在设置一个SolidColorBrush对象的属性,该属性不是aFrameworkElementFrameworkContentElement。该场景确实满足文档中的第三点(SolidColorBrush是 a Freezable,并且它Freezable作为 a 的值提供FrameworkElement)。但请注意我用粗体显示的文本。即使满足这些要求,也不能保证它会起作用。

\n\n

有趣的是,当在a 直接拥有的上下文中完成时,您似乎试图实现的基本方法确实有效(例如)。ResourceDictionaryFrameworkElementWindow

\n\n

为什么会这样,我不知道。我的猜测是,只要您处于某处的上下文中FrameworkElement 就有足够的内部状态管理来处理更新DynamicResource代理,因此它可以正常工作。

\n\n

无论如何,这意味着一种可能的解决方法是将您的资源放入,Window.Resources而不是您现在放置的任何地方。我不知道你是否可以指望它总是有效;毕竟,该文档包罗万象,让微软可以说“也许它会起作用,也许它不会”。但在我看来,这种情况不会很快被打破。

\n\n

或者,您可以修改画笔资源本身。例如:

\n\n
private void Button1_Click(object sender, RoutedEventArgs e)\n{\n    Application.Current.Resources["ForegroundBrush"] = new SolidColorBrush(Colors.Green);\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

确实符合文档中的更多要求,因此似乎更有可能适用于 .NET 的任何未来版本(我已经验证它今天确实有效)。

\n