在 WPF 中使用画笔、模板和样式等资源时,可以将它们指定为 StaticResources
<Rectangle Fill="{StaticResource MyBrush}" />
或作为 DynamicResource
<ItemsControl ItemTemplate="{DynamicResource MyItemTemplate}" />
大多数时候(总是?),只有一个有效,另一个会在运行时抛出异常。但我想知道为什么:
主要区别是什么。像内存或性能影响
WPF 中是否有“画笔始终是静态的”和“模板始终是动态的”等规则?
我认为静态与动态之间的选择并不像看起来那样随意......但我看不到这种模式。
在应用程序实际运行之前加载 XAML 期间,将解析 StaticResource 并将其分配给属性。它只会被分配一次,并且对资源字典的任何更改都会被忽略。
DynamicResource 在加载期间将一个 Expression 对象分配给该属性,但直到运行时要求该 Expression 对象提供值时才实际查找资源。这会延迟查找资源,直到在运行时需要它。一个很好的例子是对稍后在 XAML 中定义的资源的前向引用。另一个例子是直到运行时才存在的资源。如果源资源字典更改,它将更新目标。
我也对他们感到困惑。请参阅下面的示例:
<Window x:Class="WpfApplicationWPF.CommandsWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="CommandsWindow" Height="300" Width="300">
<StackPanel>
<Button Name="ButtonNew"
Click="ButtonNew_Click"
Background="{DynamicResource PinkBrush}">NEW</Button>
<Image Name="ImageNew"
Source="pack://application:,,,/images/winter.jpg"></Image>
</StackPanel>
<Window.Background>
<DynamicResource ResourceKey="PinkBrush"></DynamicResource>
</Window.Background>
</Window>
这里我为按钮和窗口使用了动态资源,并没有在任何地方声明它。运行时,将检查层次结构的ResourceDictionary。由于我没有定义它,我猜会使用默认值。
如果我将下面的代码添加到 Button 的单击事件,由于它们使用 DynamicResource,因此背景将相应更新。
private void ButtonNew_Click(object sender, RoutedEventArgs e)
{
this.Resources.Add( "PinkBrush"
,new SolidColorBrush(SystemColors.DesktopColor)
);
}
如果他们使用了 StaticResource:
资源必须在 XAML 中声明
这也是“在”他们被使用之前。
希望我消除了一些困惑。
StaticResource 将在对象构造时解决。每次控件需要资源时,都会评估和解析 DynamicResource。
StaticResource 使用第一个值。 DynamicResource 使用最后一个值。 DynamicResource 可用于嵌套样式,StaticResource 不能。
假设你有这个嵌套的 Style 字典。 LightGreen 位于根级别,而 Pink 嵌套在 Grid 中。
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style TargetType="{x:Type Grid}">
<Style.Resources>
<Style TargetType="{x:Type Button}" x:Key="ConflictButton">
<Setter Property="Background" Value="Pink"/>
</Style>
</Style.Resources>
</Style>
<Style TargetType="{x:Type Button}" x:Key="ConflictButton">
<Setter Property="Background" Value="LightGreen"/>
</Style>
</ResourceDictionary>
鉴于:
<Window x:Class="WpfStyleDemo.ConflictingStyleWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="ConflictingStyleWindow" Height="100" Width="100">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Styles/ConflictingStyle.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<Grid>
<Button Style="{DynamicResource ConflictButton}" Content="Test"/>
</Grid>
</Window>
StaticResource 会将按钮呈现为 LightGreen,这是它在样式中找到的第一个值。 DynamicResource 将在呈现网格时将 LightGreen 按钮覆盖为粉红色。
https://i.stack.imgur.com/dYc0V.png
https://i.stack.imgur.com/MLGoJ.png
请记住,VS Designer 将 DynamicResource 视为 StaticResource。它将获得第一个值。在这种情况下,VS Designer 会将按钮呈现为 LightGreen,尽管它实际上最终呈现为 Pink。
当根级样式 (LightGreen) 被移除时,StaticResource 会抛出错误。
主要区别是什么。像内存或性能影响
当底层对象发生变化时,静态资源和动态资源之间的区别就出现了。如果您在 Resources 集合中定义的 Brush 在代码中被访问并设置为不同的对象实例,则 Rectangle 将不会检测到此更改。
静态资源通过引用元素检索一次并在资源的生命周期内使用。然而,DynamicResources 每次使用时都会检索。
动态资源的缺点是它们往往会降低应用程序性能。
WPF 中是否有“画笔始终是静态的”和“模板始终是动态的”等规则?
最佳实践是使用静态资源,除非有特定原因,例如您想动态更改代码中的资源。您希望使用动态资源的另一个示例包括使用 SystemBrushes、SystenFonts 和系统参数时。
发现所有答案都很有用,只是想再添加一个用例。
在复合 WPF 方案中,您的用户控件可以通过将资源称为 DynamicResource 来使用在任何其他父窗口/控件(将承载此用户控件)中定义的资源。
正如其他人所提到的,静态资源将在编译时查找。用户控件不能引用托管/父控件中定义的那些资源。不过,在这种情况下可以使用 DynamicResource。
动态资源的重要好处
如果应用程序启动时间非常长,则必须使用动态资源,因为静态资源总是在创建窗口或应用程序时加载,而动态资源在首次使用时加载。
但是,除非您的资源非常庞大和复杂,否则您不会看到任何好处。
动态资源只能在设置的属性位于从依赖对象派生的对象上或可冻结的对象上使用,因为静态资源可以在任何地方使用。您可以使用静态资源抽象出整个控制。
在以下情况下使用静态资源:
不需要在运行时更改反应资源时。如果您需要具有大量资源的良好性能。在同一字典中引用资源时。
动态资源:
属性或样式设置器主题的值直到运行时才知道这包括系统、应用程序、基于主题的设置这也包括前向引用。引用在页面、窗口、用户控件加载时可能无法加载的大型资源。在自定义控件中引用主题样式。
It will update the target if the source resource dictionary is changed.