WPF中的StaticResource和DynamicResource有什么区别?


473

在WPF中使用画笔,模板和样式之类的资源时,可以将其指定为StaticResources

<Rectangle Fill="{StaticResource MyBrush}" />

或作为DynamicResource

<ItemsControl ItemTemplate="{DynamicResource MyItemTemplate}"  />

在大多数情况下(总是?),只有一个工作正常,而另一个在运行时会抛出异常。但我想知道为什么:

  • 主要区别是什么。像内存或性能影响
  • WPF中是否有规则,例如“画笔始终是静态的”和“模板始终是动态的”等?

认为静态与动态之间的选择并不像看上去那样随意……但是我看不到这种模式。


27
重要的是要注意,Windows 8 App开发人员没有DyanmicResource作为选项,只有StaticResource。
杰里·尼克松

2
@杰里·尼克松(Jerry Nixon)感谢上帝,我已经失去了无法工作的次数,因为我使用的是DynamicResource而不是StaticResource,反之亦然。从程序员的角度来看,这是不必要的复杂性。类比是变量定义,我是否必须明确指定它是位于堆还是堆栈上?如果我弄错了,它会引发灾难性的运行时错误?
Contango 2014年

有关StaticResource和DynamicResource以及何时使用它们的更详尽的解释,请参阅msdn.microsoft.com/zh-cn/library/ms750613%28v=vs.100%29.aspx
Michael Repucci 2015年

Answers:


466

一个静态资源将得到解决,并且应用程序实际运行前发生的XAML负荷期间分配给属性。它只会被分配一次,对资源字典的任何更改都将被忽略。

一个DynamicResource装载过程中分配一个表达式对象的属性,但实际上并没有查找资源直到运行时表达式对象要求的值。这将延迟查找资源,直到在运行时需要它为止。一个很好的例子是对XAML稍后定义的资源的前向引用。另一个例子是直到运行时才存在的资源。如果源资源字典发生更改,它将更新目标。


4
我需要使用DynamicResource之前必须进行哪些更改?以一个模板为例:我定义了一次,但是触发器和东西当然可以更改模板的内容,但是模板仍然相同。静态资源会在这里吗?
Isak Savo

5
如果要附加的资源是在XAML的使用点之前定义的,并且在应用程序运行的整个生命周期内都不会改变,请使用StaticResource。在这种情况下,使用StaticResource可以获得更好的性能。
Phil Wright

4
twoWay绑定对这两者都适用吗?如果是,在这种情况下有什么区别?
WhoIsNinja

11
最后一句话非常重要:It will update the target if the source resource dictionary is changed.
MEMark

4
@IsakSavo考虑具有颜色主题的UI,使用动态资源,您可以将一个字典替换为另一个字典,新字典中引用资源的所有内容都会自动更新。
古斯多

119

我也对他们感到困惑。请参见下面的示例:

<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>

在这里,我使用了用于按钮和窗口的动态资源,并且未在任何地方声明它。

如果我将下面的代码添加到Button的click事件中,因为它们使用DynamicResource,因此背景将相应地更新。

private void ButtonNew_Click(object sender, RoutedEventArgs e)
{
    this.Resources.Add(  "PinkBrush"
                         ,new SolidColorBrush(SystemColors.DesktopColor)
                       );
}

如果他们使用过StaticResource:

  • 必须在XAML中声明资源
  • 而且它们也被“之前”使用。

希望我能消除一些困惑。


31

StaticResource将在对象构造上解决。
每当控件需要资源时,都会对DynamicResource进行评估和解决。


21
  1. StaticResource使用第一个值。DynamicResource使用最后一个值。
  2. DynamicResource可以用于嵌套样式,StaticResource不能。

假设您有此嵌套样式字典。浅绿色位于根级别,而粉红色嵌套在网格内。

<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按钮为Pink。

静态资源 静态资源

动态资源 动态资源

请记住,VS Designer将DynamicResource视为StaticResource。它将获得第一价值。在这种情况下,VS Designer会将按钮渲染为浅绿色,尽管实际上最终会变成粉红色。

删除根级别样式(LightGreen)时,StaticResource将引发错误。


13

主要区别是什么。像内存或性能影响

静态和动态资源之间的差异是在基础对象更改时出现的。如果通过代码访问了Resources集合中定义的Brush,并将其设置为其他对象实例,则Rectangle将不会检测到此更改。

通过引用元素检索一次的静态资源,并用于资源的生命周期。而DynamicResources每次使用时都会检索。

动态资源的缺点是它们倾向于降低应用程序性能。

WPF中是否有规则,例如“画笔始终是静态的”和“模板始终是动态的”等?

最佳实践是使用静态资源,除非有特定原因,例如您想动态更改后面的代码中的资源。您希望使用动态资源的实例的另一个示例包括使用SystemBrushes,SystenFonts和System Parameters时的情况。


7

发现所有答案都很有用,只想添加一个用例。

在复合WPF方案中,您的用户控件可以通过将其他资源称为DynamicResource来使用在任何其他父窗口/控件(将要承载此用户控件)中定义的资源。

正如其他人所提到的,Staticresource将在编译时进行查找。用户控件不能引用托管/父控件中定义的那些资源。但是,在这种情况下可以使用DynamicResource。


3

动态资源的重要好处

如果应用程序启动花费的时间非常长,则必须使用动态资源,因为静态资源总是在创建窗口或应用程序时加载,而动态资源则是在首次使用时加载。

但是,除非您的资源非常庞大和复杂,否则您将看不到任何好处。


对于DynamicResources,它是否只会造成一次性能问题(第一次使用),还是每次使用该元素时都会造成性能问题?
Morgane

在这种情况下,大多数使用的字段必须是静态资源,自定义使用的字段可以是动态的,即对于主窗口资源是静态的,而对话框窗口资源可以是动态的
zamoldar

2

只有当属性设置在对象上时才可以使用动态资源,该对象是从依赖对象派生的或可冻结的,因为静态资源可以在任何地方使用。您可以使用静态资源来抽象整个控件。

在以下情况下使用静态资源:

  1. 如果不需要在运行时更改反应资源。
  2. 如果您需要具有大量资源的良好性能。
  3. 在同一词典中引用资源时。

动态资源:

  1. 在运行时才知道属性或样式设置器主题的值
    • 这包括系统,应用程序,基于主题的设置
    • 这也包括前向参考。
  2. 引用在加载页面,窗口,用户控件时可能无法加载的大型资源。
  3. 在自定义控件中引用主题样式。
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.