关于.net:WPF中的StaticResource和DynamicResource有什么区别?

What's the difference between StaticResource and DynamicResource in WPF?

在WPF中使用诸如刷子、模板和样式等资源时,可以将它们指定为staticresources

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

或者作为一种动力来源

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

大多数时候(总是?),只有一个工作,另一个将在运行时引发异常。但我想知道原因:

  • 主要区别是什么?像记忆或性能影响
  • WPF中是否有"画笔总是静态的"和"模板总是动态的"等规则?

我假设静态和动态之间的选择并不像看起来那样随意…但我看不到这种模式。


在加载应用程序实际运行之前发生的XAML期间,将解析静态资源并将其分配给属性。它将只分配一次,并且忽略对资源字典的任何更改。

在加载期间,dynamicResource将表达式对象分配给属性,但在运行时要求表达式对象提供值之前,不会实际查找资源。这会推迟查找资源,直到在运行时需要它为止。一个很好的例子是对稍后在XAML中定义的资源的正向引用。另一个例子是直到运行时才存在的资源。如果更改了源资源字典,它将更新目标。


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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<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。由于我没有定义它,我想将使用默认值。

如果我将下面的代码添加到click event of button中,因为它们使用动态源,所以背景将相应地更新。

1
2
3
4
5
6
private void ButtonNew_Click(object sender, RoutedEventArgs e)
{
    this.Resources.Add( "PinkBrush"
                         ,new SolidColorBrush(SystemColors.DesktopColor)
                       );
}

如果他们使用了StaticResource:

  • 必须在XAML中声明资源
  • 这也是"以前"使用它们的原因。

希望我能消除一些困惑。


静态资源将在对象构造上解决。每次控件需要资源时,都将评估和解决DynamicResource。


逻辑资源允许您在XAML中定义对象,这些对象不是可视树的一部分,但可以在用户界面中使用。逻辑资源的一个例子是brush,它用于提供颜色方案。通常,这些对象定义为资源,由应用程序的多个元素使用。

1
2
3
4
5
6
<Window.Resources>
    <RadialGradientBrush x:Key="myGradientBrush">
        <GradientStop Color="Green" Offset="0"/>
        <GradientStop Color="Blue" Offset="2"/>
    </RadialGradientBrush>
</Window.Resources>

现在,上述声明的资源可以用作静态或动态资源。要记住的一点是,当使用静态资源时,应该首先在XAML代码中定义它,然后才能引用它。静态和动态资源可用作:

1
<Grid Background="{StaticResource myGradientBrush}"></Grid>

或:

1
<Grid Background="{DynamicResource myGradientBrush}"></Grid>

StaticResource和DynamicResource的区别在于引用元素如何检索资源。静态资源只能由引用元素检索一次,并在资源的整个生命周期中使用。另一方面,每次使用引用的对象时都会获取动态源。

简单来说,如果radialGradientBrush的颜色属性在代码中更改为橙色和粉色,那么只有当资源用作动态源时,它才会反映在元素上。下面是更改代码中资源的代码:

1
2
3
RadialGradientBrush radialGradientBrush =
    new RadialGradientBrush(Colors.Orange, Colors.Pink);
this.Resources["myGradientBrush"] = radialGradientBrush;

DynamicResource的缺点是它会降低应用程序性能,因为每次使用时都会检索资源。最佳实践是静态资源使用,直到有特定的理由使用动态资源为止。

来源:静态资源与动态资源


  • StaticResource使用第一个值。DynamicResource使用Last值。
  • DynamicResource不能用于嵌套样式,StaticResource不能。
  • 假设您有这个嵌套样式字典。浅绿色位于根级别,而粉红色嵌套在网格中。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    <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>

    鉴于:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    <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将把按钮呈现为浅绿色,这是在样式中找到的第一个值。动态源将在渲染网格时将浅绿色按钮覆盖为粉红色。

    StaticResource静态源

    DynamicResource动态资源

    请记住,VS设计器将动态资源视为静态资源。它将得到第一个值。在这种情况下,vs designer会将按钮呈现为浅绿色,尽管它实际上是粉红色的。

    当删除根级别样式(浅绿色)时,StaticResource将抛出一个错误。


    主要区别是什么?像记忆或性能影响

    当底层对象发生更改时,静态资源和动态资源之间的差异就会出现。如果在代码中访问了资源集合中定义的画笔并将其设置为其他对象实例,则矩形将不会检测到此更改。

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

    动态资源的缺点是它们往往会降低应用程序性能。

    WPF中是否有"画笔总是静态的"和"模板总是动态的"等规则?

    最佳实践是使用静态资源,除非有特定的原因,如您希望动态更改代码隐藏中的资源。另一个不希望使用动态资源的实例示例包括使用SystemBrush、SystemEnfonts和系统参数时。


    找到所有有用的答案,只想再添加一个用例。

    在复合WPF场景中,用户控件可以使用在任何其他父窗口/控件(将承载此用户控件)中定义的资源,方法是将该资源引用为动态源。

    正如其他人提到的,静态资源将在编译时被查找。用户控件不能引用宿主/父控件中定义的资源。不过,在这种情况下可以使用动态资源。


    动态资源的重要效益

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

    但是,除非您的资源非常大并且复杂的。


    动态资源只能在设置的属性位于从依赖项对象派生的对象上或可冻结的对象上时使用,因为静态资源可以在任何位置使用。您可以使用静态资源抽象出整个控件。

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

  • 当不需要在运行时更改反应资源时。
  • 如果你需要一个有很多资源的好表现。
  • 同时引用同一字典中的资源。
  • 动态资源:

  • 直到运行时才知道属性或样式设置器主题的值
    • 这包括系统、应用、基于主题的设置
    • 这还包括转发引用。
  • 引用页面、窗口和用户控件加载时可能无法加载的大型资源。
  • 引用自定义控件中的主题样式。