如何使用 DynamicResource 更新 SolidColorBrush 颜色?
Posted
技术标签:
【中文标题】如何使用 DynamicResource 更新 SolidColorBrush 颜色?【英文标题】:How to update SolidColorBrush color with a DynamicResource? 【发布时间】:2018-01-26 04:23:46 【问题描述】:我正在尝试动态更改画笔的颜色。我写了一个非常简单的例子,但我不明白为什么它不起作用。
我在我的应用程序的 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>
然后,在我的 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>
最后在我的代码后面,我正在改变颜色:
private void Button1_Click(object sender, RoutedEventArgs e)
Application.Current.Resources["Foreground"] = Colors.Green;
很遗憾,画笔颜色没有更新。谁能解释一下为什么?
注意:我知道 如果我直接更改画笔的颜色,它可以正常工作,但我试图理解为什么使用颜色作为动态资源的 SolidColorBrush 不会更新其颜色变化时的颜色。
更新:使用样式按预期工作
如果我为文本块使用样式,只需更新颜色,它就可以正常工作并且画笔采用正确的颜色。直接使用画笔和使用样式有什么区别?
<Style TargetType="TextBlock" x:Key="TextBlockStyle">
<Setter Property="Foreground" Value="StaticResource ForegroundBrush" />
</Style>
【问题讨论】:
【参考方案1】:如果没有一个好的Minimal, Complete, and Verifiable code example 可以可靠地重现您的问题,就不可能确定问题出在哪里。但基本问题似乎是您试图以不受支持的方式使用DynamicResource
。
来自the documentation:
动态资源引用有一些明显的限制。以下至少一项必须为真:
•要设置的属性必须是 FrameworkElement 或 FrameworkContentElement 上的属性。该属性必须由 DependencyProperty 支持。
•引用是针对 StyleSetter 中的值。
•要设置的属性必须是 Freezable 上的属性,该属性作为 FrameworkElement 或 FrameworkContentElement 属性的值或 Setter 值提供。
因为要设置的属性必须是 DependencyProperty 或 Freezable 属性,所以大多数属性更改可以传播到 UI,因为属性更改(更改的动态资源值)已被属性系统确认。大多数控件都包含在 DependencyProperty 更改并且该属性可能会影响布局时强制控制另一个布局的逻辑。但是,并非所有将 DynamicResource 标记扩展作为其值的属性都可以保证以它们在 UI 中实时更新的方式提供值 [强调我的] .该功能仍可能因属性、拥有该属性的类型甚至应用程序的逻辑结构而异。
您正在为SolidColorBrush
对象设置属性,该对象不是FrameworkElement
或FrameworkContentElement
。场景确实符合文档中的第三个要点(SolidColorBrush
是 Freezable
,而 Freezable
被提供为 FrameworkElement
的值)。但请注意我加粗的文字。即使满足这些要求,也不能保证它会起作用。
有趣的是,当在ResourceDictionary
直接由FrameworkElement
拥有的上下文中完成时,您似乎试图实现的基本方法确实 工作(例如Window
) .
为什么会这样,我不知道。我的猜测是,只要您处于 FrameworkElement
somewhere 的上下文中,就有足够的内部状态管理来处理更新 DynamicResource
代理,因此它可以工作。
无论如何,这意味着一种可能的解决方法是将您的资源放入Window.Resources
,而不是您现在放置它们的任何地方。我不知道您是否可以指望此始终正常工作;毕竟,文档包含了所有内容,让微软说“也许它会工作,也许它不会”。但在我看来,这种情况可能不会很快被打破。
或者,您可以修改画笔资源本身。例如:
private void Button1_Click(object sender, RoutedEventArgs e)
Application.Current.Resources["ForegroundBrush"] = new SolidColorBrush(Colors.Green);
确实符合文档中的更多要求,因此似乎更有可能适用于任何未来版本的 .NET(我已经验证它今天确实可以使用?)。
【讨论】:
【参考方案2】:我认为这是唯一的原因,颜色是一种值类型的数据,当您从 ResourceDictionary 获取源时,它返回颜色的值(副本),重新分配的操作不会影响原始实例(资源)。 所以认为可以有很多解决方案来解决这个问题:
this.Resources["ForegroundBrush"] = new SolidColorBrush(Colors.Green);
Or
var brush = this.Resources["ForegroundBrush"] as SolidColorBrush;
if(brush != null)
brush.Color = Colors.Green;
【讨论】:
如果我使用文本块的样式,只需更新颜色,就可以正常工作。以上是关于如何使用 DynamicResource 更新 SolidColorBrush 颜色?的主要内容,如果未能解决你的问题,请参考以下文章
StaticResource和DynamicResource使用
[WPF]静态资源(StaticResource)和动态资源(DynamicResource)
[WPF]静态资源(StaticResource)和动态资源(DynamicResource)
DynamicResource 和 StaticResource